2012-05-10 138 views
7

我正在Delphi中進行自定義控件(繼承自TCustomControl),它由多個多邊形列表項(不規則形狀)組成。我需要爲每個項目實現鼠標事件,但首先我需要能夠檢測鼠標位置是否在給定的多邊形內(array of TPoint)。我正在捕捉Hit Test消息(WM_NCHITTEST),這是我需要進行此驗證的地方。我有多個多邊形,我將在每個多邊形項目中執行循環,並執行此檢查以查看鼠標的X/Y位置是否在此多邊形內。確定點是否在多邊形內?

procedure TMyControl.WMNCHitTest(var Message: TWMNCHitTest); 
var 
    P: TPoint; //X/Y of Mouse 
    Poly: TPoints; //array of TPoint 
    X: Integer; //iterator 
    I: TMyListItem; //my custom list item 
begin 
    P.X:= Message.XPos; 
    P.Y:= Message.YPos; 
    for X := 0 to Items.Count - 1 do begin 
    I:= Items[X]; //acquire my custom list item by index 
    Poly:= I.Points; //acquire polygon points 

    //Check if Point (P) is within Polygon (Poly)...? 

    end; 
end; 
+0

只需指出,我只是在分配'P.X'和'P.Y'後丟失了一行代碼'P:= ScreenToClient(P);'。這將這些點從相對於屏幕轉換爲相對於控件。 –

+0

當然它可以像'P:= ScreenToClient(Point(Message.XPos,Message.YPos));'(將3行代碼合併成一個)那樣簡單 –

回答

15

您可以使用PtInRegion

function PointInPolygon(Point: TPoint; const Polygon: array of TPoint): Boolean; 
var 
    rgn: HRGN; 
begin 
    rgn := CreatePolygonRgn(Polygon[0], Length(Polygon), WINDING); 
    Result := PtInRegion(rgn, Point.X, Point.Y); 
    DeleteObject(rgn); 
end; 
+0

這也是我的第一個想法。我假設創建一個GDI區域的開銷不算太壞(?)。 –

+4

@Andreas我不認爲這個開銷很糟糕。 GDI地區應該非常輕便。如果這是一個問題,那麼你可以緩存區域旁邊的多邊形。 –

+0

非常好!我不會有太多的開銷問題,因爲我不希望這個控件擁有超過20個列表項(這對於此控件來說已經是一個大數字)。 –

1

檢查點是否在多邊形內可以通過想象一個水平線穿過該點,然後從左到右計算這條想象線穿過多邊形的次數。如果在碰到點前多邊形的交叉數是奇數,那麼點就在裏面,如果連點都在多邊形之外。

0

還有一種我們廣泛使用的技術,它根本不涉及任何數學運算,並且可以處理任何形狀的極其複雜的嵌入式控件。只需將控件的屏幕外圖像與用戶可點擊的所有部件進行顏色編碼(如下圖所示)即可。

當他們移動鼠標時,只需在屏幕外的圖像中查看鼠標下方像素的顏色,並告訴我們它們所處的按鍵/控制鍵是否超過了白色,以及任何系列各種部分的顏色。

Color mask

//僞代碼

function MouseOverControl(LocalMousePos:TPoint):ControlID; 
begin 
    //sanity check 
    Result:=IDNull; 
    if (LocalMouse.X < 0) or (LocalMouse.X > ControlWidth) or 
     (LocalMouse.Y < 0) or (LocalMouse.Y > ControlHeight) then 
      exit; 
    case OffScreenControlMask.Canvas.Pixels[LocalMousePos.X,LocalMousePos.Y] of 
    clwhite:exit; 
    clRed:result:=ControlIDOne; 
    clGreen:result:=ControlIDTwo; 
    clBlue:result:=ControlIDThree; 
    ... etc 
    end; 
end; 

注意:所附的彩色掩膜圖像表示分解成象限具有中心按鈕五個相同圓形對照(並且因爲它們都使用相同的顏色我們對每種顏色都有常量,並且我們通過一個簡單的XPosition來確定五個鼠標中的哪一個已經結束)以及右側的附加不規則控制以及下方的一組或一組矩形按鈕。

相關問題