Hello friends, In this article you will learn two basic concept of Regions. 1. Creating Region from a Bitmap. 2. Hit Testing within a Region.
Creating Region from a Bitmap
In my previous article Working with Region API you learned how to create regions of different shapes. Now in this article we will talk more complex technique to create more complex skinned regions using Bitmap.
You can use a Bitmap to define your region and then you can apply this region to any window (for skin it will be form). To define region from a bitmap you have to define a mask color in a Bitmap. Points with mask color in the loaded bitmap will be ignored when you create a region. |
Click here to copy the following block | Option Explicit
Private Const DIB_RGB_COLORS As Long = 0& Private Const FLOODFILLSURFACE As Long = 1& Private Const RGN_DIFF As Long = 4& Private Const OBJ_BITMAP As Long = 7& Private Const RDH_RECTANGLES As Long = &H1& Private Const RGN_HDR_OFFSET As Long = &H8&
Private Enum RgnHdr dwSize iType nCount nRgnSize rcLeft rcTop rcRight rcBottom End Enum
Private Type BITMAPINFOHEADER biSize As Long biWidth As Long biHeight As Long biPlanes As Integer biBitCount As Integer biCompression As Long biSizeImage As Long biXPelsPerMeter As Long biYPelsPerMeter As Long biClrUsed As Long biClrImportant As Long End Type
Private Type RGBQUAD rgbBlue As Byte rgbGreen As Byte rgbRed As Byte rgbReserved As Byte End Type
Private Type BITMAPINFOC bmiHeader As BITMAPINFOHEADER bmiColors As RGBQUAD End Type
Private Type BITMAPINFO bmiHeader As BITMAPINFOHEADER End Type
Private Type BITMAP bmType As Long bmWidth As Long bmHeight As Long bmWidthBytes As Long bmPlanes As Integer bmBitsPixel As Integer bmBits As Long End Type
Private Type ColorRef Blue As Byte Green As Byte Red As Byte End Type
Private Type RECT left As Long top As Long right As Long bottom As Long End Type
Private mRgnData() As Long Private mlDataSize As Long Private mlDataPosn As Long
Private Declare Function ExtCreateRegion Lib "gdi32" ( _ ByRef lpXform As Any, ByVal nCount As Long, _ ByRef lpRgnData As Any) As Long
Private Declare Function GetDIBits Lib "gdi32" ( _ ByVal aHDC As Long, ByVal hBitmap As Long, _ ByVal nStartScan As Long, ByVal nNumScans As Long, _ lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" ( _ ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function SetWindowRgn Lib "user32.dll" ( _ ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function SetCapture Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function PtInRegion Lib "gdi32.dll" ( _ ByVal hRgn As Long, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" ( _ ByVal hObject As Long) As Long
Private Declare Function CreateEllipticRgnIndirect Lib "gdi32.dll" ( _ lpRect As RECT) As Long
Private Declare Function InvertRgn Lib "gdi32.dll" ( _ ByVal hdc As Long, ByVal hRgn As Long) As Long
Private bMoving As Boolean Private sngXStart As Single Private sngYStart As Single Private WndRect As RECT, RetVal As Long
Dim hRgnSkin As Long, hRgnCloseButton As Long
Private Sub Form_Load() hRgnSkin = CreateMaskRgn(Me.Picture.Handle, RGB(255, 0, 128)) SetWindowRgn hWnd, hRgnSkin, True
WndRect.left = 118 WndRect.top = 46 WndRect.right = 130 WndRect.bottom = 58
hRgnCloseButton = CreateEllipticRgnIndirect(WndRect)
Timer1.Enabled = True Timer1.Interval = 500 End Sub
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single) If PtInRegion(hRgnCloseButton, x / 15, y / 15) Then End End If
If Button <> 1 Then Exit Sub SetCapture Me.hWnd sngXStart = x sngYStart = y bMoving = True
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single) If Not bMoving Then Exit Sub Me.Move Me.left - sngXStart + x, Me.top - sngYStart + y End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single) If Not bMoving Then Exit Sub ReleaseCapture bMoving = False End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) If bMoving = True Then ReleaseCapture
DeleteObject hRgnCloseButton DeleteObject hRgnSkin End Sub
Public Function CreateMaskRgn(ByVal hBmp As Long, ByVal lMaskColor As Long) As Long
Dim bInRgn As Boolean Dim lX As Long Dim lY As Long Dim lRet As Long Dim lIdx As Long Dim lWidth As Long Dim lHeight As Long Dim lMaxPxls As Long Dim lStartX As Long Dim lPosY As Long Dim hRgn As Long Dim laPixels() As Long Dim sTemp As String Dim bmImage As BITMAP Dim bmiImage As BITMAPINFO Dim hdc As Long
hdc = GetDC(0)
lRet = GetObjectAPI(hBmp, Len(bmImage), bmImage) lWidth = bmImage.bmWidth lHeight = bmImage.bmHeight
If (lWidth > 0) And (lHeight > 0) Then lMaxPxls = lWidth * lHeight ReDim laPixels(lMaxPxls - 1)
With bmiImage.bmiHeader .biSize = 40 .biWidth = lWidth .biHeight = lHeight .biPlanes = 1 .biBitCount = 32 .biCompression = 0 .biClrUsed = 0 .biClrImportant = 0 .biSizeImage = lMaxPxls End With
lRet = GetDIBits(hdc, hBmp, 0, lHeight, _ laPixels(0), bmiImage, DIB_RGB_COLORS)
sTemp = right("000000" & Hex$(lMaskColor), 6) sTemp = Mid$(sTemp, 5, 2) & Mid$(sTemp, 3, 2) & Mid$(sTemp, 1, 2) lMaskColor = Val("&H" & sTemp & "&")
Call ClearRects
For lY = 0 To lHeight - 1 lIdx = lY * lWidth lPosY = (lHeight - 1) - lY bInRgn = False
For lX = 0 To lWidth - 1 If ((laPixels(lIdx) And &HFFFFFF) = lMaskColor) Then If bInRgn Then Call AddRect(lStartX, lPosY, lX, lPosY + 1) bInRgn = False End If Else If Not bInRgn Then lStartX = lX bInRgn = True End If End If lIdx = lIdx + 1 Next
If bInRgn Then Call AddRect(lStartX, lPosY, lWidth, lPosY + 1) End If Next
hRgn = CreateRegion() End If
Erase laPixels CreateMaskRgn = hRgn Call ClearRects End Function
Private Sub ClearRects() ReDim mRgnData(RGN_HDR_OFFSET - 1) mlDataSize = RGN_HDR_OFFSET - 1 mlDataPosn = RGN_HDR_OFFSET
mRgnData(RgnHdr.dwSize) = 32 mRgnData(RgnHdr.iType) = RDH_RECTANGLES
mRgnData(RgnHdr.rcLeft) = &H7FFFFFFF mRgnData(RgnHdr.rcTop) = &H7FFFFFFF mRgnData(RgnHdr.rcRight) = &H80000000 mRgnData(RgnHdr.rcBottom) = &H80000000 End Sub
Private Sub AddRect(ByVal lLeft As Long, ByVal lTop As Long, ByVal lRight As Long, ByVal lBottom As Long) If mlDataPosn > (mlDataSize - 4) Then mlDataSize = mlDataSize + 200 ReDim Preserve mRgnData(mlDataSize - 1) As Long End If
mRgnData(mlDataPosn) = lLeft mRgnData(mlDataPosn + 1) = lTop mRgnData(mlDataPosn + 2) = lRight mRgnData(mlDataPosn + 3) = lBottom
If (lLeft < mRgnData(RgnHdr.rcLeft)) Then mRgnData(RgnHdr.rcLeft) = lLeft If (lRight > mRgnData(RgnHdr.rcRight)) Then mRgnData(RgnHdr.rcRight) = lRight If (lTop < mRgnData(RgnHdr.rcTop)) Then mRgnData(RgnHdr.rcTop) = lTop If (lBottom > mRgnData(RgnHdr.rcBottom)) Then mRgnData(RgnHdr.rcBottom) = lBottom
mlDataPosn = mlDataPosn + 4 End Sub
Private Function CreateRegion() As Long If (mlDataSize <= RGN_HDR_OFFSET) Then Exit Function
ReDim Preserve mRgnData(mlDataPosn - 1)
mRgnData(RgnHdr.nCount) = Int((mlDataPosn - RGN_HDR_OFFSET) \ 4) mRgnData(RgnHdr.nRgnSize) = mRgnData(RgnHdr.nCount) * 16
CreateRegion = ExtCreateRegion(ByVal 0&, mRgnData(RgnHdr.dwSize) _ + mRgnData(RgnHdr.nRgnSize), mRgnData(0)) End Function
Private Sub l8_Click() Shell "explorer http://www.binaryworld.net", vbNormalFocus End Sub
Private Sub Timer1_Timer() InvertRgn hdc, hRgnCloseButton Me.Refresh End Sub |
|