Quando o mouse passa por cima de um componente (um TButton, por exemplo) se a propriedade ShowHint for True e houver algum texto na propriedade Hint, a janela Hint/ToolTip será exibida para o componente.
Por design do Windows, mesmo se fixamos o valor da propriedade Hint para um item de Menu, o popup do Hint não será exibido. Porém, os itens de menu Iniciar exibem Hints, e o menu Favoritos do Internet Explorer também exibe hints de itens de menu.
Está bastante normal utilizar o evento OnHint da variável global Application, em aplicações Delphi, para exibir hints (longos) de itens de menu em uma barra de estado.
O Windows não expõe as mensagens necessárias para suportar um evento OnMouseEnter tradicional.
Se quisermos adicionar hints popups de item de menu (tooltips) aos menus de aplicações Delphi, precisamos “apenas” controlar apropriadamente a mensagem WM_MenuSelect.
A classe TMenuItemHint - Hints para itens de menu!
Já que não podemos confiar no método Application.ActivateHint para exibir a janela de hint para itens de menu (pois o tratamento de menus é completamente controlando pelo Windows), para exibir a janela de hint, temos que criar nossa própria versão da mesma - derivando uma nova classe THintWindow.
Vejamos como criar uma classe TMenuItemHint - uma viúva de hint, que de fato é exibida para itens de menu! Em primeiro lugar, precisamos controlar a mensagem Windows WM_MENUSELECT:
type
TForm1 = class(TForm)
...
private
procedure WMMenuSelect(var Msg: TWMMenuSelect) ; message WM_MENUSELECT;
end
...
implementation
...
procedure TForm1.WMMenuSelect(var Msg: TWMMenuSelect) ;
var
menuItem : TMenuItem;
hSubMenu : HMENU;
begin
inherited; // from TCustomForm (so that Application.Hint is assigned)
menuItem := nil;
if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then
begin
if Msg.MenuFlag and MF_POPUP = MF_POPUP then
begin
hSubMenu := GetSubMenu(Msg.Menu, Msg.IDItem);
menuItem := Self.Menu.FindItem(hSubMenu, fkHandle);
end
else
begin
menuItem := Self.Menu.FindItem(Msg.IDItem, fkCommand);
end;
end;
miHint.DoActivateHint(menuItem);
end; (*WMMenuSelect*)
Informação rápida: a mensagem WM_MENUSELECT é enviada para janela owner do menu (Form1!), quando o usuário seleciona (não clica!) um item de menu. Usando o método FindItem da classe TMenu, podemos obter o item de menu atualmente selecionado. Os parâmetros do FindItem tem relação com as propriedades da mensagem recebida.
Uma vez que saibamos qual o item de menu por onde o mouse está passando, chamamos o método DoActivateHint da classe TMenuItemHint.
Nota: a variável miHint está definida como “var miHint: TMenuItemHint" e é criada no tratador de evento OnCreate do Formulário.
Agora, só resta a implementar a classe TMenuItemHint. Vejamos a parte da interface:
TMenuItemHint = class(THintWindow)
private
activeMenuItem: TMenuItem;
showTimer: TTimer;
hideTimer: TTimer;
procedure HideTime(Sender: TObject);
procedure ShowTime(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
procedure DoActivateHint(menuItem: TMenuItem);
destructor Destroy; override;
end;
Basicamente, a função DoActivateHint chama o método ActivateHint do THintWindow que usa a propriedade Hint do TMenuItem (se for designada).
O showTimer é usado para garantir que o HintPause (da Application) ocorra antes do hint ser exibido. O hideTimer usa Application.HintHidePause para esconder a janela hint depois de um intervalo especificado.
Quando usaríamos Hints de Itens de Menu ?
Apesar de que alguém poderia dizer que não é um bom projeto para exibir hints de itens de menu, há situações onde a exibição de hints de itens de menu, de fato é muito melhor do que usar uma barra de estado. Uma lista de itens de menus “mais recentemente usados” (Most Recently Used - MRU) é tal caso. Um menu de barra de tarefa personalizado é outro.
Crie uma nova aplicação Delphi. No formulário principal coloque um MainMenu ("Menu1") (paleta Standard), um StatusBar (paleta Win32) e um ApplicationEvents (paleta Aditional).
Acrescente vários itens de menu ao menu. Designe uma propriedade Hint para alguns itens de menu, deixe alguns itens de menu "livres" de Hint.
A seguir, o código de fonte completo da unit, junto com a implementação da classe TMenuItemHint:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms,Dialogs, Menus, AppEvnts,
StdCtrls, ExtCtrls, ComCtrls;
type
TMenuItemHint = class(THintWindow)
private
activeMenuItem: TMenuItem;
showTimer: TTimer;
hideTimer: TTimer;
procedure HideTime(Sender: TObject);
procedure ShowTime(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
procedure DoActivateHint(menuItem: TMenuItem) ;
destructor Destroy; override;
end;
TForm1 = class(TForm)
...
procedure FormCreate(Sender: TObject) ;
procedure ApplicationEvents1Hint(Sender: TObject);
private
miHint : TMenuItemHint;
procedure WMMenuSelect(var Msg: TWMMenuSelect); message WM_MENUSELECT;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
miHint := TMenuItemHint.Create(self);
end; (*FormCreate*)
procedure TForm1.ApplicationEvents1Hint(Sender: TObject) ;
begin
StatusBar1.SimpleText := 'App.OnHint : ' + Application.Hint;
end; (*Application.OnHint*)
procedure TForm1.WMMenuSelect(var Msg: TWMMenuSelect) ;
var
menuItem: TMenuItem;
hSubMenu: HMENU;
begin
inherited; // from TCustomForm (ensures that Application.Hint is assigned)
menuItem := nil;
if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then
begin
if Msg.MenuFlag and MF_POPUP = MF_POPUP then
begin
hSubMenu := GetSubMenu(Msg.Menu, Msg.IDItem) ;
menuItem := Self.Menu.FindItem(hSubMenu, fkHandle) ;
end
else
begin
menuItem := Self.Menu.FindItem(Msg.IDItem, fkCommand) ;
end;
end;
miHint.DoActivateHint(menuItem) ;
end; (*WMMenuSelect*)
{ TMenuItemHint }
constructor TMenuItemHint.Create(AOwner: TComponent) ;
begin
inherited;
showTimer := TTimer.Create(self) ;
showTimer.Interval := Application.HintPause;
hideTimer := TTimer.Create(self) ;
hideTimer.Interval := Application.HintHidePause;
end; (*Create*)
destructor TMenuItemHint.Destroy;
begin
hideTimer.OnTimer := nil;
showTimer.OnTimer := nil;
self.ReleaseHandle;
inherited;
end; (*Destroy*)
procedure TMenuItemHint.DoActivateHint(menuItem: TMenuItem) ;
begin
//force remove of the "old" hint window
hideTime(self) ;
if (menuItem = nil) or (menuItem.Hint = '') then
begin
activeMenuItem := nil;
Exit;
end;
activeMenuItem := menuItem;
showTimer.OnTimer := ShowTime;
hideTimer.OnTimer := HideTime;
end; (*DoActivateHint*)
procedure TMenuItemHint.ShowTime(Sender: TObject) ;
var
r: TRect;
wdth: integer;
hght: integer;
begin
if activeMenuItem <> nil then
begin
//position and resize
wdth := Canvas.TextWidth(activeMenuItem.Hint) ;
hght := Canvas.TextHeight(activeMenuItem.Hint) ;
r.Left := Mouse.CursorPos.X + 16;
r.Top := Mouse.CursorPos.Y + 16;
r.Right := r.Left + wdth + 6;
r.Bottom := r.Top + hght + 4;
ActivateHint(r,activeMenuItem.Hint) ;
end;
showTimer.OnTimer := nil;
end; (*ShowTime*)
procedure TMenuItemHint.HideTime(Sender: TObject) ;
begin
//hide (destroy) hint window
self.ReleaseHandle;
hideTimer.OnTimer := nil;
end; (*HideTime*)
end.
Nenhum comentário:
Postar um comentário