PureBasic

윈도우 (폼) 모양 바꾸기 - 2 (png 배경 이미지)

홍사훈     0건     306회

본문

역시 region을 지정하는 방법입니다.

 

레이어 창에 UpdateLayeredWindow API를 사용하는 방식과 차이는, 

 1. 투명, 불투명 두 가지만 적용 가능. 즉, 반투명한 픽셀 표현 불가. 

 2. 창 하나에 가젯(컨트롤)을 올려서 사용할 수 있음. 정도가 되겠습니다. 

 

   8b66e02d2b4883e265286d1e6f50633e_1433947
 

UsePNGImageDecoder()

 

Structure myRGNDATA

  rdh.RGNDATAHEADER

  Buffer.RECT[0]

EndStructure

 

Structure myARGB

  Blue.a

  Green.a

  Red.a

  Alpha.a

EndStructure

 

 

Procedure CreateBitmapRgn(Image)

  Protected *old, *RgnData.myRGNDATA, *buf.myARGB, rt.RECT

  Protected x, y, height, width, RectIdx, PixelFormat, Pitch, UBound, hRgn

  

  If IsImage(Image)

    height = ImageHeight(Image) - 1

    width = ImageWidth(Image) - 1

    

    ;*RgnData\Buffer[] 배열의 마지막 인덱스 저장.

    UBound = height

    

    ;메모리 할당.

    *RgnData = AllocateMemory(SizeOf(RGNDATAHEADER) + (UBound + 1) * SizeOf(RECT))

    If *RgnData

      If (height >= 0 And width >= 0) And StartDrawing(ImageOutput(Image))

        ;픽셀 데이터 구함.

        *buf = DrawingBuffer()

        If *buf ;데이터 못 구했으면 함수 종료.

          PixelFormat = DrawingBufferPixelFormat()

          If PixelFormat & #PB_PixelFormat_32Bits_BGR  ;32비트 BGR 이미지가 아니면 함수 종료.

            Pitch = DrawingBufferPitch() / 4 - 1 ;메모리에서의 x축 실제 바이트 수 / 4 - 1.

            ;Debug pitch

            ;Debug width

            

            If PixelFormat & #PB_PixelFormat_ReversedY  ;상하 바뀐 이미지이면 아래부터 시작함.

              y = height

            EndIf

            

            Repeat

              ;새 시작값 설정.

              rt\left = -1

              rt\top = y

              rt\bottom = y + 1

              

              For x = 0 To Pitch

                If x <= width  ;이미지의 너비까지만 처리함.

                  If *buf\Alpha < 255 ;불투명한 픽셀이 아니면.

                    If rt\left >= 0  ;직전에 불투명한 픽셀이었다면 현재까지의 영역을 새 rect로 추가.

                      rt\right = x

                      If RectIdx > UBound

                        UBound + height

                        *old = *RgnData

                        *RgnData = ReAllocateMemory(*RgnData, SizeOf(RGNDATAHEADER) + (UBound + 1) * SizeOf(RECT))

                        ;메모리 할당 실패면 종료.

                        If *RgnData = 0 : FreeMemory(*old) : ProcedureReturn 0 : EndIf

                      EndIf

                      *RgnData\Buffer[RectIdx] = rt

                      RectIdx + 1

                      rt\left = -1  ;새 시작값으로 설정.

                    EndIf

                    

                  Else ;불투명한 픽셀이면.

                    If rt\left < 0  ;시작값이 없으면 새 시작 위치로 지정.

                      rt\left = x

                    EndIf

                    

                  EndIf

                  

                EndIf

                ;다음 픽셀 데이터 위치로 포인터 변경.

                *buf + SizeOf(myARGB)

              Next

              

              If rt\left >= 0 ;현재 x축의 끝인데 시작 값이 초기화되지 않았다면 새 rect로 추가.

                rt\right = width

                If RectIdx > UBound

                  UBound + height

                  *old = *RgnData

                  *RgnData = ReAllocateMemory(*RgnData, SizeOf(RGNDATAHEADER) + (UBound + 1) * SizeOf(RECT))

                  ;메모리 할당 실패면 종료.

                  If *RgnData = 0 : FreeMemory(*old) : ProcedureReturn 0 : EndIf

                EndIf

                *RgnData\Buffer[RectIdx] = rt

                RectIdx + 1

              EndIf

              

              If PixelFormat & #PB_PixelFormat_ReversedY  ;상하 바뀐 이미지이면.

                y - 1

                If y < 0 : Break : EndIf

              Else

                y + 1

                If y > height : Break : EndIf

              EndIf

            ForEver

            

            ;복합 region 생성.

            *RgnData\rdh\dwSize = SizeOf(RGNDATAHEADER)

            *RgnData\rdh\iType = #RDH_RECTANGLES

            *RgnData\rdh\nCount = RectIdx

            *RgnData\rdh\nRgnSize = RectIdx * SizeOf(RECT)

            hRgn = ExtCreateRegion_(0, *RgnData\rdh\dwSize + *RgnData\rdh\nRgnSize, *RgnData)

          EndIf

        EndIf

        StopDrawing()

      EndIf

      FreeMemory(*RgnData)

    EndIf

  EndIf

  

  ProcedureReturn hRgn

EndProcedure

 

 

 

; If CreateImage(0, 400, 400, 32)

;   If StartDrawing(ImageOutput(0))

;     DrawingMode(#PB_2DDrawing_AllChannels)

;     Box(0, 0, 400, 400, $FFFF00FF)

;     Box(50, 50, 300, 300, $00FF00FF)

;     Circle(200, 60, 60, $FF0000FF)

;     Ellipse(200, 200, 90, 40, $440000FF)

;     StopDrawing()

;     hRgn = CreateBitmapRgn(0)

;   EndIf

; EndIf

 

If LoadImage(0, "clock.png")

  ;이미지로 region 생성.

  hRgn = CreateBitmapRgn(0)

Else

  Debug "이미지 없음"

  End

EndIf

 

If OpenWindow(0, 0, 0, ImageWidth(0), ImageHeight(0), "test", #WS_SYSMENU | #WS_MINIMIZEBOX | #PB_Window_BorderLess | #PB_Window_ScreenCentered | #PB_Window_Invisible)

  ImageGadget(0, 0, 0, 0, 0, ImageID(0))

  DisableGadget(0, 1)

  

  ;Windows XP 같은 경우, region이 복잡하면 창과 그 아래 가려진 부분을 그리고 지우는 데 매우 반응이 느리므로 레이어 윈도우 속성을 적용해야 빠름.

  SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0), #GWL_EXSTYLE) | #WS_EX_LAYERED)

  SetLayeredWindowAttributes_(WindowID(0), 0, 255, #LWA_ALPHA)

  

  hBtnExit = ButtonGadget(1, 50, 90, 90, 30, "프로그램 종료")

  hBtnMin = ButtonGadget(2, 50, 130, 90, 30, "최소화")

  

  If hRgn

    ;가젯의 클라이언트 좌표, 영역 구함.

    GetClientRect_(hBtnExit, @rcBtn.RECT)

    ;부모 윈도우 좌표로 변환.

    MapWindowPoints_(hBtnExit, WindowID(0), @rcBtn, 2)

    ;버튼 가젯 region 생성.

    hRgnBtnExit = CreateRectRgnIndirect_(@rcBtn)

    

    ;가젯의 클라이언트 좌표, 영역 구함.

    GetClientRect_(hBtnMin, @rcBtn.RECT)

    ;부모 윈도우 좌표로 변환.

    MapWindowPoints_(hBtnMin, WindowID(0), @rcBtn, 2)

    ;버튼 가젯 region 생성.

    hRgnBtnMin = CreateRectRgnIndirect_(@rcBtn)

    

    ;region 결합.

    CombineRgn_(hRgn, hRgn, hRgnBtnExit, #RGN_OR)

    CombineRgn_(hRgn, hRgn, hRgnBtnMin, #RGN_OR)

    DeleteObject_(hRgnBtnExit)

    DeleteObject_(hRgnBtnMin)

    

    ;창에 region 설정.

    SetWindowRgn_(WindowID(0), hRgn, 1)

  EndIf

  

  HideWindow(0, 0)

  

  Repeat

    Event = WaitWindowEvent()

    

    Select Event

      Case #PB_Event_Gadget

        EventGadget = EventGadget()

        EventType = EventType()

        

        If EventType = #PB_EventType_LeftClick

          If EventGadget = 1  ;종료 버튼.

            Break

          EndIf

          

          If EventGadget = 2  ;최소화 버튼.

            SetWindowState(0, #PB_Window_Minimize)

          EndIf

        EndIf

        

      Case #PB_Event_CloseWindow ;창 닫기. (Alt + F4 등으로)

        Break

        

      Case #WM_LBUTTONDOWN  ;창에서 왼 버튼 누르고 드래그하여 창 이동.

        SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)

    EndSelect

    

  ForEver

  

  CloseWindow(0)

  

  DeleteObject_(hRgn) ;시스템이 알아서 제거하므로 지울 필요는 없다는 듯.

  

EndIf

 

[이 게시물은 최고관리자님에 의해 2023-04-15 20:44:39 PureBasic에서 이동 됨]

등록된 댓글이 없습니다.



Copyrightⓡ1996~2025, sahoon.com All Rights Reserved.