Solved

how to catch the mouse right button event in TMenuitem

Posted on 2003-10-29
10
637 Views
Last Modified: 2010-04-05
Dear sir,

i want to write a new class TCatchMouseMenuItem which is inherited from TMenuitem. TCatchMouseMenuitem could catch the right mouse button event. please help me

thanks

Tuan Le
0
Comment
Question by:letuanle
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
10 Comments
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 9648343
TMenu bases on a Windows menu.
The problem is that Windows menues use their own private window and window handler function.
No easy way to penetrate.
Try to do some tricks with WM_ENTERMENULOOP, WM_EXITMENULOOP and WM_ENTERIDLE.

Menu Messages
The following messages are used with menus.
 
WM_COMMAND  
WM_CONTEXTMENU  
WM_DRAWITEM  
WM_ENTERMENULOOP  
WM_EXITMENULOOP  
WM_INITMENU  
WM_INITMENUPOPUP  
WM_MEASUREITEM  
WM_MENUCHAR  
WM_MENUSELECT  
WM_NEXTMENU  
WM_SYSCOMMAND  
0
 

Author Comment

by:letuanle
ID: 9648763
thanks for your answer. I wonder

 TControl = class(TComponent)
 TMenuItem = class(TComponent)

but TControl can catch rightmouse event, TMenuitem is not

i have already read the implementation of TControl and TMenuitem in menus.pas and controls.pas but i can not understand where is the code which TControl can do it

please explain me more, thank you very much

Tuan Le
0
 
LVL 6

Expert Comment

by:GloomyFriar
ID: 9648969
The code looks like that:


procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;

procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
begin
  SendCancelMode(Self);
  inherited;
  if csCaptureMouse in ControlStyle then MouseCapture := True;
  if csClickEvents in ControlStyle then Include(FControlState, csClicked);
  DoMouseDown(Message, mbLeft, []);
end;

procedure TControl.DoMouseDown(var Message: TWMMouse; Button: TMouseButton;
  Shift: TShiftState);
begin
  if not (csNoStdEvents in ControlStyle) then
    with Message do
      MouseDown(Button, KeysToShiftState(Keys) + Shift, XPos, YPos);
end;

procedure TControl.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
end;

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Expert Comment

by:DeerBear
ID: 9649590
Hi,

You could try( be very cautious ) with substituting the Window Procedure for the
menu. Yes, it's not going to be fun, but it may make your job done.

Plus, you have to keep in mind that right button mouse clicks make very
little sense in a menu system.

Maybe if you can elaborate on what you want to achieve, we may be very
well able to help you better.

HTH,

Andrew
0
 
LVL 34

Expert Comment

by:Slick812
ID: 9653012
hello letuanle, this is not so easy, but you might look at the code for this EE question -

http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20394288.html

this will get the right mouse click for a menu item. . . Ask questions if you need more information about this
0
 

Author Comment

by:letuanle
ID: 9654828
Dear GloomyFriar,

it is not easy as you think. I already override the wndproc and catch the
WM_RBUTTONDOWN event but it never goes there.

thanks,
Tuan Le
------------------------
Comment from GloomyFriar
Date: 10/30/2003 02:39AM PST  Comment    

The code looks like that:


procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;

procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
begin
  SendCancelMode(Self);
  inherited;
  if csCaptureMouse in ControlStyle then MouseCapture := True;
  if csClickEvents in ControlStyle then Include(FControlState, csClicked);
  DoMouseDown(Message, mbLeft, []);
end;

procedure TControl.DoMouseDown(var Message: TWMMouse; Button: TMouseButton;
  Shift: TShiftState);
begin
  if not (csNoStdEvents in ControlStyle) then
    with Message do
      MouseDown(Button, KeysToShiftState(Keys) + Shift, XPos, YPos);
end;

procedure TControl.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
end;


 
0
 
LVL 34

Expert Comment

by:Slick812
ID: 9654862
menus are a "Separate" system object and DO NOT send ANY mouse messages to any window any where
0
 
LVL 34

Expert Comment

by:Slick812
ID: 9654878
robert_marquardt has given you many of the Menu messages that are sent to the owner window for menu events or notifucations, No mouse messages in that bunch
0
 
LVL 34

Accepted Solution

by:
Slick812 earned 500 total points
ID: 9655438
here is some code to get a Right Mouse Click form a Menu Item. This uses a WH_MOUSE  Hook to get mouse events of this process, This Hook is started whenever the Main menu is activated with the WM_ENTERMENULOOP message, and the hook is stopped on the WM_EXITMENULOOP message. You will need some method to determime which sub-menu of the Main-Menu is currently showing, that is done with the WM_INITMENUPOPUP message and saving the handle of the sub-menu in the wParam.
The HookFunc function is where the hook messages are tested, I use the MainMenu1.Items[0].Handle to test if that sub-menu is up, but you will need to change that to the sub-menu or menus handles you are interested in. The MenuItemFromPoint function will get the menu Item number for the Point position of the right mouse click, and I test it for Menu Item Zero, but you will need to change this test to one or more menu items that you need.


  private
    { Private declarations }
    hMenuUp: Integer;
    procedure EnterMenu(var Msg: TMessage); message WM_ENTERMENULOOP;
    procedure ExitMenu(var Msg: TMessage); message WM_EXITMENULOOP;
    procedure InitMenu(var Msg: TMessage); message WM_INITMENUPOPUP;


function HookFunc(Code, wParam: Integer; var MouseStrut: TMOUSEHOOKSTRUCT): Integer; stdcall;
var
MenuItem: cardinal;
begin
Result:=CallNextHookEx(hMHook, Code, wParam, Integer(@MouseStrut));
if Code < 0 then Exit;
{this test for the Right button Up and if the hMenuUp if the first sub-menu in the main menu}
if (Code = HC_ACTION) and (wParam = WM_RBUTTONUP) and
    (Form1.hMenuUp = Form1.MainMenu1.Items[0].Handle) then
      begin
   {get the menu item of the of the sub-menu clicked on}
      MenuItem := Cardinal(windows.MenuItemFromPoint(Form1.Handle, Form1.MainMenu1.Items[0].Handle, MouseStrut.pt));
      if MenuItem = 0 then // if Top Menu Item then write some numbers on the Label for a Right click on that Item
        Form1.Label1.Caption := 'WOW '+IntToStr(MouseStrut.pt.x)+'  '+IntToStr(MouseStrut.pt.y)+'  '+IntToStr(MenuItem) else
        Form1.Label1.Caption := 'Not Item zero';

      end;
end;


procedure TForm1.InitMenu(var Msg: TMessage);
var
MRect: TRect;
begin
Msg.Result := 0;
hMenuUp := Msg.WParam;
{get the handle of the sub-menu that is showing in the hMenuUp}
end;

procedure TForm1.EnterMenu(var Msg: TMessage);
begin
{start the hook when the menu is shown}
Msg.Result := 0;
if (Msg.WParam = 0) and (hMHook = 0) then
hMHook := SetWindowsHookEx(WH_MOUSE, @HookFunc, hInstance, 0);
end;

procedure TForm1.ExitMenu(var Msg: TMessage);
begin
{kill hook on menu close}
Msg.Result := 0;
if hMHook <> 0 then
if UnhookWindowsHookEx(hMHook) then
hMHook := 0;
end;

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
you might try it out. it works for me
0
 
LVL 34

Expert Comment

by:Slick812
ID: 9655448
seems like I forgot this

var
  Form1: TForm1;
  hMHook: Integer;

implementation

{$R *.DFM}
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question