Solved

how to catch the mouse right button event in TMenuitem

Posted on 2003-10-29
10
613 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
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
 
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 33

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
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

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 33

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 33

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 33

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 33

Expert Comment

by:Slick812
ID: 9655448
seems like I forgot this

var
  Form1: TForm1;
  hMHook: Integer;

implementation

{$R *.DFM}
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

758 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now