在Delphi XE2中,如何检测用户是否用鼠标左键或鼠标右键单击了一个弹出菜单项?检测菜单项上的左/右鼠标按钮是否点击?
0
A
回答
1
使用此设备,将其作为组件安装,并替换标准TPopupMenu
,该标准增加了一个OnMenuRightClick
事件。
unit RCPopupMenu;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Menus;
type
TMenuRightClickEvent = procedure (Sender: TObject; Item: TMenuItem) of object;
TRCPopupList = class(TPopupList)
protected
procedure WndProc(var Message: TMessage); override;
end;
TRCPopupMenu = class(TPopupMenu)
private
FOnMenuRightClick: TMenuRightClickEvent;
protected
function DispatchRC(aHandle: HMENU; aPosition: Integer): Boolean;
procedure RClick(aItem: TMenuItem);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Popup(X, Y: Integer); override;
published
property OnMenuRightClick: TMenuRightClickEvent read FOnMenuRightClick write FOnMenuRightClick;
end;
procedure Register;
var
RCPopupList: TRCPopupList;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TRCPopupMenu]);
end;
{ TRCPopupList }
procedure TRCPopupList.WndProc(var Message: TMessage);
var
i: Integer;
pm: TPopupMenu;
begin
if Message.Msg = WM_MENURBUTTONUP then
begin
for I := 0 to Count - 1 do
begin
pm := TPopupMenu(Items[i]);
if pm is TRCPopupMenu then
if TRCPopupMenu(Items[i]).DispatchRC(Message.lParam, Message.wParam) then
Exit;
end;
end;
inherited WndProc(Message);
end;
{ TRCPopupMenu }
constructor TRCPopupMenu.Create(AOwner: TComponent);
begin
inherited;
PopupList.Remove(Self);
RCPopupList.Add(Self);
end;
destructor TRCPopupMenu.Destroy;
begin
RCPopupList.Remove(Self);
PopupList.Add(Self);
inherited;
end;
function TRCPopupMenu.DispatchRC(aHandle: HMENU; aPosition: Integer): Boolean;
begin
Result := False;
if Handle = aHandle then
begin
RClick(Items[aPosition]);
Result := True;
end;
end;
procedure TRCPopupMenu.Popup(X, Y: Integer);
const
Flags: array[Boolean, TPopupAlignment] of Word =
((TPM_LEFTALIGN, TPM_RIGHTALIGN, TPM_CENTERALIGN),
(TPM_RIGHTALIGN, TPM_LEFTALIGN, TPM_CENTERALIGN));
Buttons: array[TTrackButton] of Word = (TPM_RIGHTBUTTON, TPM_LEFTBUTTON);
var
AFlags: Integer;
begin
DoPopup(Self);
AFlags := Flags[UseRightToLeftAlignment, Alignment] {or Buttons[TrackButton]};
if (Win32MajorVersion > 4) or ((Win32MajorVersion = 4) and (Win32MinorVersion > 0)) then
begin
AFlags := AFlags or (Byte(MenuAnimation) shl 10);
AFlags := AFlags or TPM_RECURSE;
end;
TrackPopupMenuEx(Items.Handle, AFlags, X, Y, RCPopupList.Window, nil);
end;
procedure TRCPopupMenu.RClick(aItem: TMenuItem);
begin
if Assigned (FOnMenuRightClick) then
FOnMenuRightClick(Self, aItem);
end;
var
oldPL: TPopupList;
initialization
RCPopupList := TRCPopupList.Create;
finalization
RCPopupList.Free;
end.
然后,您可以使用OnMenuRightClick
事件上右击执行一些动作!
注意:我没有制作这个单元 - 我不知道是谁做的,但是信用可以交给谁做......不过我已经在Delphi XE2中测试过了,它工作正常。
0
弹出式菜单处理发生在user32.dll
内部的函数TrackPopupMenu
中,该函数是Windows的一部分。响应左键或右键单击,将生成一个WM_COMMAND
消息,该消息由Delphi VCL框架代码处理。 wParam
参数包含正在执行的菜单项的索引,并且LParam
似乎始终为零。
您的唯一方法是创建一个对左右单击不同响应的菜单,而不是从Windows生成弹出式菜单。
如果Windows的设计者决定将这些信息作为窗口消息中的WParam或LParam的一部分传递给您,那么您可能会对此做出某些操作,或者如果您可以钩住鼠标按下事件弹出菜单的窗口消息循环的一部分,你也许可以做到这一点,但我不知道这样做的可靠方法。
如果您确实需要对左右菜单进行不同的处理,创建自己的弹出式菜单可能会减少工作量。但是,然后没有用户会知道如何使用您的应用程序。我不推荐这样的想法,事实上,我不能用任何我知道的方法,用标准的Win32菜单。
1
感谢TLama和该代码的作者!非常有用,但只需要一个小的更新: 该过程只是检查项目的第一级,如果你的菜单包含子项,它不工作... 所以我们必须重载DispatchRC函数做一个递归搜索被点击的项目。 我这样做,并能正常工作:
function TRCPopupMenu.DispatchRC(aHandle: HMENU; aPosition: Integer): Boolean;
begin
//Result := False; // freezebit : now, unused value
if Handle = aHandle then
begin
RClick(Items[aPosition]);
Result := True;
Exit; // freezebit : found, so leave
end;
Result := DispatchRC(aHandle, aPosition, Items); // freezebit : now make a recursive search in all sub-items
end;
// freezebit : this function search in all sub-items recursively if we found the right-clicked TMenuItem
function TRCPopupMenu.DispatchRC(aHandle: HMENU; aPosition: Integer; aItems: TMenuItem): Boolean;
var
i: integer;
itm: TMenuItem;
begin
Result := False;
for i := 0 to aItems.Count - 1 do begin
itm := aItems[i];
if itm.Count = 0 then
Continue;
if itm.Items[0].Parent.Handle = aHandle then begin
RClick(itm.Items[aPosition]);
Result := True;
Exit;
end;
if DispatchRC(aHandle, aPosition, itm) then begin
Result := True;
Exit;
end;
end;
end;
-1
感谢作者和freezebit,但我觉得有点精美的这一解决方案(也改变DispatchRC):
function TRCPopupMenu.DispatchRC(aHandle: HMENU; aPosition: Integer): Boolean;
var FParentItem: TMenuItem;
begin
Result := False;
if Handle = aHandle then
FParentItem := Items
else
FParentItem := FindItem(aHandle, fkHandle);
if FParentItem <> nil then
begin
RClick(FParentItem.Items[aPosition]);
Result := True;
end;
{ if Handle = aHandle then
begin
RClick(Items[aPosition]);
Result := True;
end;}
end;
相关问题
- 1. 如何检测鼠标点击一个按钮,下拉菜单
- 2. Win32:如何在同一时间点击左右鼠标按钮
- 3. 我可以检测鼠标左键吗?或Ctrl +右键点击?
- 4. 检测左右两侧同时点击鼠标?
- 5. 检测鼠标左键按
- 6. 是否有可能检测到右键单击浏览器上下文菜单上的左键单击?
- 7. QT:在QGraphicsItem上检测左右鼠标按下事件
- 8. 如何检测左右按钮是否被按下?
- 9. 如何检测鼠标是否移动到左侧或右侧?
- 10. Visual C++检测右键单击按钮
- 11. 如何检测按钮上的鼠标右键?
- 12. 如何检测鼠标是否在菜单栏上?
- 13. 单击按钮上的菜单项
- 14. 鼠标点击按钮
- 15. QListView点击鼠标按钮
- 16. 检测额外的鼠标按钮批量点击
- 17. 检测鼠标后退/前进按钮的点击
- 18. GLUT鼠标点击检测
- 19. 检测鼠标点击
- 20. SFML鼠标点击检测
- 21. 的ListView与单选按钮火灾/加薪的SelectionChanged ONLY上单击鼠标右键(需要左键单击)
- 22. 我想检测用户是否点击图像的左上角,右上角,左下角或右下角部分。
- 23. 鼠标右键单击按钮应该执行左键单击按钮(jquery)的动作
- 24. 测试在C++中鼠标左键和右键点击
- 25. 如果不点击,在主窗口是零,发射后右,右鼠标点击,弹出菜单项
- 26. 如何检测鼠标左键单击,但在UI上发生单击时没有按钮组件
- 27. 如何检测按钮单击后的鼠标移动事件
- 28. 检查哪个鼠标按钮被按下,是否双击?
- 29. 在发送鼠标左键后,检测鼠标左键按下
- 30. 检测鼠标左键是否在表格之外按住
滑稽 - 我只是发现了这个相同的组件2分钟前在: http://www.delphipages.com/forum/showthread.php?t=180337 – user1580348
但是,无论如何非常感谢你! – user1580348
@ user1580348 - 非常欢迎。 – Shambhala