我在Delphi 7中使用TStringGrid有一个怪异的行为。
如果将弹出菜单与网格关联,则Delphi不会调用OnMouseUp事件。基本上,当按下RMB时,菜单的弹出会以某种方式取消/延迟OnMouseUp。实际上,为了达到100%的准确度,下次您按下鼠标按钮时,将两次调用OnMouseUp-一次是针对当前事件,一次是针对丢失/延迟的事件。
这将破坏程序的整个逻辑,因为当用户按下鼠标按钮时,下一次将调用不需要的代码。
最佳答案
上下文菜单的自动弹出是对鼠标右键单击的响应。相同的点击也会触发OnMouseUp
事件。 VCL开发人员可以选择在显示弹出窗口之前或之后触发“ OnMouseUp”事件。显然后者是有效的,即在关闭弹出窗口时触发该事件(通过鼠标或键盘,例如按“ Esc”键)。
事件没有加倍,当您按下向左按钮以关闭弹出窗口时,您通过释放向左按钮再次触发“ OnMouseUp”事件。
您有几种选择。一种是派生一个新类并重写MouseDown
方法来触发您自己的事件。一个例子;
type
TMyStringGrid = class(TStringGrid)
private
FOnRButtonUp: TMouseEvent;
protected
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
published
property OnRButtonUp: TMouseEvent read FOnRButtonUp write FOnRButtonUp;
end;
[...]
procedure TStringGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
if (Button = mbRight) and Assigned(FOnRButtonUp) then
FOnRButtonUp(Self, Button, Shift, X, Y);
inherited;
end;
另一种选择是处理
VM_RBUTTONUP
消息。这可以通过如上所述派生一个新类或替换网格的WindowProc
来完成。在此here中有一个替换WindowProc question的示例。另一种选择是不让鼠标上移事件留下来,而是在弹出菜单的
OnPopup
事件中进行处理。在显示弹出窗口之前会触发此事件。您可以使用Mouse.CursorPos
获取鼠标坐标。另外,另一种选择是将弹出菜单的
AutoPopup
属性设置为False
,并在OnMouseUp
事件(或者更好的是在OnContextMenu
事件中)首先进行一些处理,然后显示弹出窗口。一个例子;procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Pt: TPoint;
begin
// Do processing
if Button = mbRight then begin
Pt := (Sender as TStringGrid).ClientToScreen(Point(X, Y));
PopupMenu1.Popup(Pt.X, Pt.Y);
end;
end;