Pergunta

Então, eu tenho um TMenuItem anexado a um TAction em um TPopupMenu para um TDBGrid (na verdade, de terceiros, mas você entendeu).Com base na linha selecionada na grade, a TAction é habilitada ou desabilitada.O que eu quero é poder exibir uma dica ao usuário explicando porque o item está desabilitado.

Quanto ao motivo pelo qual quero uma dica sobre um item de menu desativado, digamos apenas que estou de acordo com Joel.

Todos os TMenuItem têm uma propriedade de dica, mas pelo que posso dizer, eles são usados ​​apenas no manipulador de eventos TApplicationEvent.OnHint para inserir a dica em um TStatusBar ou algum outro processamento especial.EU encontrei um artigo sobre como criar sua própria janela par para TMenuItems de um TMainMenu, mas isso não funciona em um TMenuItem de TPopupMenu.Funciona manipulando a mensagem WM_MENUSELECT, que até onde sei não é enviada em um TPopupMenu.

Foi útil?

Solução

WM_MENUSELECT também é tratado para itens de menu em menus pop-up, mas não pelo proc do Windows do formulário que contém o menu (pop-up), mas por uma janela auxiliar invisível criada por Menus.PopupList.Felizmente você pode (pelo menos no Delphi 5) obter esse HWND via Menus.PopupList.Window.

Agora você pode usar a maneira antiga de criar subclasses de uma janela, conforme descrito, por exemplo, neste Artigo do CodeGear, para manipular WM_MENUSELECT também para menus pop-up.O HWND será válido após a criação do primeiro TPopupMenu até antes da destruição do último objeto TPopupMenu.

Um teste rápido com o aplicativo de demonstração no artigo vinculado à pergunta deve revelar se isso vai funcionar.

Editar: Realmente funciona.eu mudei o exemplo vinculado para mostrar dicas também para o menu pop-up.Aqui estão as etapas:

Adicione um manipulador para OnDestroy, uma variável de membro para o antigo window proc e um método para o novo window proc ao formulário:

TForm1 = class(TForm)
  ...
  procedure FormCreate(Sender: TObject);
  procedure FormDestroy(Sender: TObject);
  procedure ApplicationEvents1Hint(Sender: TObject);
private
  miHint : TMenuItemHint;
  fOldWndProc: TFarProc;
  procedure WMMenuSelect(var Msg: TWMMenuSelect); message WM_MENUSELECT;
  procedure PopupListWndProc(var AMsg: TMessage);
end;

Altere o manipulador OnCreate do formulário para subclassificar a janela PopupList oculta e implemente a restauração adequada do processo de janela no manipulador OnDestroy:

procedure TForm1.FormCreate(Sender: TObject);
var
  NewWndProc: TFarProc;
begin
  miHint := TMenuItemHint.Create(self);

  NewWndProc := MakeObjectInstance(PopupListWndProc);
  fOldWndProc := TFarProc(SetWindowLong(Menus.PopupList.Window, GWL_WNDPROC,
    integer(NewWndProc)));
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  NewWndProc: TFarProc;
begin
  NewWndProc := TFarProc(SetWindowLong(Menus.PopupList.Window, GWL_WNDPROC,
    integer(fOldWndProc)));
  FreeObjectInstance(NewWndProc);
end;

Implemente o processo de janela subclasse:

procedure TForm1.PopupListWndProc(var AMsg: TMessage);

  function FindItemForCommand(APopupMenu: TPopupMenu;
    const AMenuMsg: TWMMenuSelect): TMenuItem;
  var
    SubMenu: HMENU;
  begin
    Assert(APopupMenu <> nil);
    // menuitem
    Result := APopupMenu.FindItem(AMenuMsg.IDItem, fkCommand);
    if Result = nil then begin
      // submenu
      SubMenu := GetSubMenu(AMenuMsg.Menu, AMenuMsg.IDItem);
      if SubMenu <> 0 then
        Result := APopupMenu.FindItem(SubMenu, fkHandle);
    end;
  end;

var
  Msg: TWMMenuSelect;
  menuItem: TMenuItem;
  MenuIndex: integer;
begin
  AMsg.Result := CallWindowProc(fOldWndProc, Menus.PopupList.Window,
    AMsg.Msg, AMsg.WParam, AMsg.LParam);
  if AMsg.Msg = WM_MENUSELECT then begin
    menuItem := nil;
    Msg := TWMMenuSelect(AMsg);
    if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then begin
      for MenuIndex := 0 to PopupList.Count - 1 do begin
        menuItem := FindItemForCommand(PopupList.Items[MenuIndex], Msg);
        if menuItem <> nil then
          break;
      end;
    end;
    miHint.DoActivateHint(menuItem);
  end;
end;

Isso é feito para todos os menus pop-up em um loop, até que o primeiro item ou submenu correspondente seja encontrado.

Outras dicas

Não tenho certeza se isso ajuda, mas criei minha própria janela de dicas multilinhas (para Delphi7) para poder mostrar mais do que apenas uma linha de texto.É de código aberto e você pode encontrá-lo aqui.

Há algum trabalho envolvido em mostrá-lo no local correto da tela, mas você tem controle total sobre ele.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top