Home > Blockchain >  How to show the hint of a first-level TMainMenu item on MouseOver without opening the menu?
How to show the hint of a first-level TMainMenu item on MouseOver without opening the menu?

Time:07-03

In a 32-bit VCL Application in Windows 10 in Delphi 11 Alexandria, I have a TMainMenu with a hint on each menu item:

enter image description here

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus, Vcl.AppEvnts;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    mFile: TMenuItem;
    mEdit: TMenuItem;
    mOpen: TMenuItem;
    ApplicationEvents1: TApplicationEvents;
    procedure ApplicationEvents1Hint(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  CodeSiteLogging;

procedure TForm1.ApplicationEvents1Hint(Sender: TObject);
begin
  CodeSite.Send('TForm1.ApplicationEvents1Hint: Application.Hint', Application.Hint);
end;

end.

This is the DFM:

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 366
  ClientWidth = 639
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -15
  Font.Name = 'Segoe UI'
  Font.Style = []
  Menu = MainMenu1
  Position = poScreenCenter
  ShowHint = True
  PixelsPerInch = 120
  TextHeight = 20
  object MainMenu1: TMainMenu
    Left = 248
    Top = 144
    object mFile: TMenuItem
      Caption = 'File'
      Hint = 'Click here to open the File menu'
      object mOpen: TMenuItem
        Caption = 'Open'
        Hint = 'Click here to open a File'
      end
    end
    object mEdit: TMenuItem
      Caption = 'Edit'
      Hint = 'Click here to open the Edit menu'
    end
  end
  object ApplicationEvents1: TApplicationEvents
    OnHint = ApplicationEvents1Hint
    Left = 248
    Top = 160
  end
end

When I hover the mouse pointer over the "File" menu item, there is NO Application hint! Only after OPENING the File menu, I do get an Application.Hint when hovering the mouse pointer over the "File" menu item.

So how can I get notified when hovering the mouse pointer over the mFile menu item without opening the menu?

CodePudding user response:

If you only want to react on mouse cursor movements (and not on keyboard input) then process the WM_NCMOUSEMOVE message:

interface

  TfrmMain= class( TForm )
    mnuMain: TMainMenu;  // The menu, containing at least one top item
  protected
    procedure WmNcMouseMove(var vMsg: TWMNCMouseMove); message WM_NCMOUSEMOVE;
  end;

implementation

procedure TfrmMain.WmNcMouseMove(var vMsg: TWMNCMouseMove);
var
  iItem: Integer;
  vR: TRect;
  oItem: TMenuItem;
begin
  inherited;

  // Only react to menu related mouse cursor moves
  if vMsg.HitTest= HTMENU then begin
    oItem:= nil;  // Not found yet

    for iItem:= 0 to self.mnuMain.Items.Count- 1 do begin  // All topmost items
      if GetMenuItemRect( self.Handle, self.mnuMain.Handle, iItem, vR ) then begin
        // Also checking Y is needed, as a menu can have more than 1 line.
        // Consider sizing your window width to the minimum to see this effect.
        if (vMsg.XCursor>= vR.Left) 
        and(vMsg.XCursor<= vR.Right)
        and(vMsg.YCursor>= vR.Top)
        and(vMsg.YCursor<= vR.Bottom) then begin
          oItem:= self.mnuMain.Items[iItem];  // Found the item under the mouse cursor
          break;
        end;
      end else break;  // Makes no sense to continue on any error
    end;

    // Now get the .hint or otherwise display empty text
    if oItem<> nil then self.Caption:= oItem.Hint else self.Caption:= '';
  end;
end;
  • Successfully tested with Delphi 7 on Windows 7 x64 with themes disabled (Windows 95 look), 1 monitor only and the menu having 1 or even 2 lines (very short window width): hovering the mouse cursor over the menu items without clicking them will display the correct hint.
  • Maybe a desktop spanning multiple monitors needs additional work.
  • Covering keyboard input (Alt or F10) is already done with your code (TApplicationEvents.OnHint).
  • Discovered GetMenuItemRect() in Delphi: Menu Hint bug
    and WM_NCMOUSEMOVE in Not receiving WM_NCHitTest on title bar.

CodePudding user response:

I changed the logic of your idea which is great!

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus,
  Vcl.AppEvnts, Vcl.ComCtrls;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    mFile: TMenuItem;
    mEdit: TMenuItem;
    mOpen: TMenuItem;
    StatusBar1: TStatusBar;
    ApplicationEvents1: TApplicationEvents;
    procedure ApplicationEvents1Hint(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    procedure WmNcMouseMove(var vMsg: TWMNCMouseMove); message WM_NCMOUSEMOVE;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  CodeSiteLogging;

procedure TForm1.ApplicationEvents1Hint(Sender: TObject);
begin
  StatusBar1.SimpleText := Application.Hint;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  StatusBar1.SimpleText := '';
end;

procedure TForm1.WmNcMouseMove(var vMsg: TWMNCMouseMove);
var
  iItem: Integer;
  vR: TRect;
  oItem: TMenuItem;
begin
  inherited;

  if vMsg.HitTest = HTMENU then
  begin
    oItem := nil;

    for iItem := 0 to Self.MainMenu1.Items.Count - 1 do
    begin
      if GetMenuItemRect(Self.Handle, Self.MainMenu1.Handle, iItem, vR) then
      begin
        if (vMsg.XCursor >= vR.Left) and (vMsg.XCursor <= vR.Right) and (vMsg.YCursor >= vR.Top) and (vMsg.YCursor <= vR.Bottom) then
        begin
          oItem := Self.MainMenu1.Items[iItem];
          BREAK;
        end;
      end
      else
        BREAK;
    end;

    if Assigned(oItem) then
      StatusBar1.SimpleText := oItem.Hint;
  end;
end;

end.

What do you think?

  • Related