2012-05-10 140 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来确定五个鼠标中的哪一个已经结束)以及右侧的附加不规则控制以及下方的一组或一组矩形按钮。

相关问题