将鼠标光标捕捉到Delphi自定义控件中的一行

时间:2012-02-17 01:42:00

标签: delphi drawing custom-controls mouse mouse-cursor

我想知道如何实现水平(或垂直)捕捉鼠标光标到一条线。例如,在Facebook时间轴功能上,当您将鼠标悬停在中心线上时,它会将光标捕捉到中心。将鼠标靠近该线也可以捕捉它。

我想将它包装在一个自定义控件中,而不是表单的控件。将有一条垂直或水平线,当它到达任何地方时它必须将鼠标光标捕捉到它。我将添加返回被点击的行的位置的事件。此控件还将具有与此行平行的垂直或水平滚动条,并且两个滚动条将永远不会同时显示。是否显示此行 vertical horizo​​ntal 是一个主属性。

鼠标实际上不应该移动位置,但只是光标的显示应该以某种方式调整到显示它在该行的中心,而实际的X(或Y)位置永远不会改变。我不想移动光标,如果光线到达任何地方,我想显示光标在此行的中心。当光标处于此捕捉位置时,它将显示另一个自定义光标而不是标准(或默认)箭头。

我需要知道的是,在这个控件中,如何处理鼠标指针进入该行附近的事件,并将光标的显示调整到该行的中心。

2 个答案:

答案 0 :(得分:5)

捕捉要求您捕捉某些内容

    在AutoCAD中
  • ,“光标”实际上是与“光标”
  • 相交的水平和垂直线
  • Photoshop使用Windows鼠标,但将效果与指南
  • 对齐
  • Facebook将一个 + 标志点击到时间轴上的某个位置

您需要跟踪鼠标的位置(即OnMouseMove),如果光标“足够接近”,您可以决定该做什么。

这是一个小示例程序,其中我有一条假想的垂直线,距离左边150px。如果我足够接近那条线,会出现一点Facebook +

enter image description here

const
    centerLine = 150; //"line" is at 150px from the left
    tolerance = 15; //15px on either size is about good.

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
    if IsMouseNearLine(x, y) then
    begin
        //We're on the centerline-ish. React by...
        //...changing the cursor to a <->
        Self.Cursor := crSizeWE;

        //and maybe let's put a "+" there, like Facebook
        if (FPlusLabel = nil) then
        begin
            FPlusLabel := TLabel.Create(Self);
            FPlusLabel.Parent := Self;
            FPlusLabel.Caption := '+';
            FPlusLabel.Alignment := taCenter;
            FPlusLabel.Font.Color := $00996600; //Windows UX "Main Instruction" color
            FPlusLabel.Font.Style := FPlusLabel.Font.Style + [fsBold];
        end;

        FPlusLabel.Left := centerLine-(FPlusLabel.Width div 2);
        FPlusLabel.Top := Y-(FPlusLabel.Height div 2);
        FPlusLabel.Visible := True;
    end
    else
    begin
        Self.Cursor := crDefault;
        if Assigned(FPlusLabel) then
            FPlusLabel.Visible := False;
    end;
end;

function TForm1.IsMouseNearLine(X, Y: Integer): Boolean;
begin
    if (x >= (centerLine-tolerance)) and (x <= (centerLine+tolerance)) then
    begin
        //we're close-ish to the line
        Result := true;
    end
    else
        Result := False;
end;

当你有其他控件时,事情开始变得毛茸茸,每个控件都需要与MouseMove消息一起播放。但是,如果你将它们全部转发给一个处理程序,它就不会坏;在执行之前执行client-to-screen-to-formClient。

  

注意:任何代码都会发布到公共域中。无需归属。

答案 1 :(得分:1)

我能看到的最简单的方法是使用自己的Cursor属性创建一个TPaintBox控件,这样你就可以隐藏内置的窗口光标,并且你的所有者在它的“snapped”位置绘制了“+”符号。

鼠标指针永远不会被移动,但当真正的鼠标指针位于TPaintBox的控件范围内时,它会被所有者绘制的光标图像“替换”。