Mouse是否處於不規則區域內
來源:cww
如果有一個不規則的封閉區域,我們如何確定Mouse是在該範圍之內呢?假設有一區域
如下:
   +----+ P3 (110, 30)
   |    |
   |    |
P6+-+    +--+ P1(150,70)
 |         /
P7+-----+  /	
      P8 \/
          * P0 (100,100)

上面的這個區域,是由9個點所圍成的(* 及 +  代表點),我們以* 的那個點為P0,以反時鍾
方向循行各個點,分別是P1到P8,其螢幕座標如下:
點  = ( X ,  Y )
P0  = (100, 100) P1  = (150, 70) P2  = (110, 70) P3  = (110, 30) P4  = (50, 30)   
P5  = (50, 70)  P6  = ( 30, 70) P7  = (30, 85)  P8  = (85, 85)

假設有一個點(Px, Py),那這個點有沒有落在該區呢?這需要使用Region的觀念,PtInRegion
 API 函數可用來檢驗某個點標是否位於某一區域內,PtInRegion API函數含有三個參數,
參數一須傳入 hRegion(handle of Region,區域代碼)、參數二、三傳入位置 (X, Y),如果
 (X, Y) 位於 hRegion 所定義的區域之內,則 PtInRegion 傳回非0的值,否則傳回 0

Declare Function PtInRegion Lib "gdi32" (ByVal hRgn As Long, ByVal X As Long, ByVal Y As Long) As Long

那麼剩下的就是hRegion如何取得了,有以下幾種方式:
 hRegion  = CreateRectRgn(Px1, Py1,Px2, Py2)   產生一矩形Region ,(Px1, Py1)  (Px2,Py2)是矩形的角兩點

 hRegion  = CreateRectRgn(Px1, Py1,Px2, Py2)
      則是 建立圓形Region,(Px1, Py1)  (Px2,Py2)「圍住圓形之最小方形的兩個對角」

而本例中的9個點則是
p(0).X = 100: p(0).Y = 100
p(1).X = 150: p(1).Y = 70
p(2).X = 110: p(2).Y = 70
p(3).X = 110: p(3).Y = 30
p(4).X = 50: p(4).Y = 30
p(5).X = 50: p(5).Y = 70
p(6).X = 30: p(6).Y = 70
p(7).X = 30: p(7).Y = 85
p(8).X = 85: p(8).Y = 85

' 參數一傳入陣列,參數二傳入點數,參數三指定成 ALTERNATE 常數
hRegion = CreatePolygonRgn(p(0), 9, ALTERNATE)

好了,這個東東另外可應用於何處呢?第一個,它可以用在於Region中顯示圖形,也就是
說,如果您的Region是不規則的或圓形的,那麼該圖就會只顯示Region範圍,這需另外用

Call FillRgn(hdc, hRegion, hBrush)

第三個參數是hBrush,那代表於hDc的hRegion區域中,以hBrush的Brush將該Region填滿,
如果是NT,那麼hBrush可以是一個很大的BitMap圖,但95只能是一個8*8的BitMap,超過了
也沒有用,所以了,在NT中,我們可以將一個大大的圖,畫在Region中,而且超出Region
的部份不會畫出來,那是否很有趣?而95的使用者就沒有辦法看到。如果,您使用SelectObject
如: Call  SelectObject ( form1.hDc, hRegion ) 
那麼,您在form1上的繪圖,就被局限在hRegion所指的範圍,畫不出去了。例如上例中

me.ScaleMode = 3
hRegion = CreatePolygonRgn(p(0), 9, ALTERNATE)
Call SelectObject(Me.hDc, hRegion)
Me.Line (10, 70) - (200, 70) 

原本會在(10,70) - (200, 70) 有一條水平線,但是,現在會發現線條僅在hRegion所指的區域中
出現,這個留給您Testing;如果單只這個功能還沒有什麼,不同的Region尚可以合併成
一個Region,而且可以選擇使用and、or、xor、diff、copy的方式來合併,(使用以下API)
 Declare Function CombineRgn Lib "gdi32" Alias "CombineRgn" _
                                   (ByVal hDestRgn As Long, _
                                    ByVal hSrcRgn1 As Long, _
                                    ByVal hSrcRgn2 As Long, _
                                    ByVal nCombineMode As Long) As Long

Public Const RGN_AND = 1
Public Const RGN_COPY = 5
Public Const RGN_DIFF = 4
Public Const RGN_OR = 2
Public Const RGN_XOR = 3

如此設計出來的Region之形狀可能就變得很複雜,在上繪圖便會有特殊效果。這個我也沒
有範例,若有興趣的人可以試看看,而後將程式碼給我,以便分享。


另外,更可以用在不規則形Button的 模擬,怎麼做呢,首先,您需自行畫不規則的圖,
看您的Form需幾個這種Button就同時畫在同一張圖,並安排好其位置,因為這張圖等一下
要當作Form的底圖,如此,該Form就有表面上看來有不規則的Button了,而再來便是定義
該不規則區域的Region,產生hRegion,而後便可以在Form_MouseDown中來模擬Mouse按
下的效果了。
最後,我也用這個技術模擬Run Time中移動Line 物件,記不記得Line物件只能在Design Time
中來改變位置、大小,Run Time時只能乾瞪眼,這看一下Run Time 移動Line物件
Option Explicit

Const ALTERNATE = 1
Const WINDING = 2

Private Type POINTAPI
        X As Long
        Y As Long
End Type

Private Declare Function CreateEllipticRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function CreatePolygonRgn Lib "gdi32" (lpPoint As POINTAPI, ByVal nCount As Long, ByVal nPolyFillMode As Long) As Long
Private Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function PtInRegion Lib "gdi32" (ByVal hRgn As Long, ByVal X As Long, ByVal Y As Long) As Long

Private Declare Function FillRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long, ByVal hBrush As Long) As Long
Private Declare Function CreatePatternBrush Lib "gdi32" (ByVal hBitmap As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long

Dim hRegion As Long
Dim hBrush As Long
Dim pic1 As New StdPicture
Private Sub Command1_Click()
Call FillRgn(Me.hdc, hRegion, hBrush)
End Sub

Private Sub Form_Load()
Dim p(8) As POINTAPI
Me.ScaleMode = 3
p(0).X = 100: p(0).Y = 100
p(1).X = 150: p(1).Y = 70
p(2).X = 110: p(2).Y = 70
p(3).X = 110: p(3).Y = 30
p(4).X = 50: p(4).Y = 30
p(5).X = 50: p(5).Y = 70
p(6).X = 30: p(6).Y = 70
p(7).X = 30: p(7).Y = 85
p(8).X = 85: p(8).Y = 85
hRegion = CreatePolygonRgn(p(0), 9, ALTERNATE)
hBrush = CreateSolidBrush(RGB(255, 0, 0)) '在95中用這一行
' 如果是NT的使用者,可以改用以下兩行,並自行更動圖形檔
'   Set pic1 = LoadPicture("e:\logo.bmp")
'    hBrush = CreatePatternBrush(pic1.Handle)

End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If PtInRegion(hRegion, X, Y) Then
        Debug.Print "In 在多邊形區域"
    End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
DeleteObject hRegion
DeleteObject hBrush
End Sub