윈도우 (폼) 모양 바꾸기 - 2 (png 배경 이미지)홍사훈 0건 306회 15-06-10 23:37 |
관련링크
본문
역시 region을 지정하는 방법입니다.
레이어 창에 UpdateLayeredWindow API를 사용하는 방식과 차이는,
1. 투명, 불투명 두 가지만 적용 가능. 즉, 반투명한 픽셀 표현 불가.
2. 창 하나에 가젯(컨트롤)을 올려서 사용할 수 있음. 정도가 되겠습니다.
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
등록된 댓글이 없습니다.