Как воздействовать на контекстное меню?
    , "отменить","вырезать","копировать",...
  ![]()  | 
Наши проекты:
 Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту  | 
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS | 
| [216.73.216.5] | 
 
 | 
		
  | 
    
  
 MSDN Library 
 FAQ раздела 
 Поиск по разделу  
  Как правильно задавать вопросы| Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) | 
    Как воздействовать на контекстное меню?
    , "отменить","вырезать","копировать",...
  | 
         
         
         
          
           Сообщ.
           #1
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Здравствуйте. У меня такой вопрос - как "воздействовать" на стандартное меню, которое появляется при нажатии правой кнопки мыши в поле для ввода текста ("отменить","вырезать","копировать" и т.д.), например, в TEdit, TF1Book. В смысле, запретить/разрешить 1 из пуктов. По идее, надо ловить какое-то сообщение, но не знаю, какое. Думал - WM_CONTEXTMENU, WM_INITMENUPOPUP, нет, не то  
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #2
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата    The EnableMenuItem function enables, disables, or grays the specified menu item.  BOOL EnableMenuItem( HMENU hMenu, // handle to menu UINT uIDEnableItem, // menu item to enable, disable, or gray UINT uEnable // menu item flags );  | 
    
| 
         
         
         
          
           Сообщ.
           #3
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Эта функция получает хэндл меню и разрешает/запрещает его пункты. Как мне получить HMENU, если это не моё меню, т. е. в программе я его не создаю?  
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #4
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          vet, HMENU родного меню EDIT'а, имхо ты никак не получишь. Можешь просто задать свое PopupMenu для TEdit'а 
        
      ![]() ![]() Edit1.PopupMenu:=PopupMenu1; и делать с ним все, что душа пожелает.  | 
    
| 
         
         
         
          
           Сообщ.
           #5
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Krid @  vet, HMENU родного меню EDIT'а, имхо ты никак не получишь. Да ну брось ты, нет ничего не возможного ![]() ![]() ![]() unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,   Dialogs, StdCtrls, Menus; type   TForm1 = class(TForm)     Edit1: TEdit;   private     procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU;   end; var   Form1: TForm1; implementation var  HookHandle: DWORD = 0; {$R *.dfm} function MsgProc(Code: Integer; WParam: Integer; LParam: PCWPStruct): Integer; stdcall; var   Menu: HMENU;   ItemCount, I: Integer; begin   if (Code = HC_ACTION) then     case LPARAM.message of       WM_MENUSELECT:       begin         Menu := LParam^.lParam; // Вот он хэндл меню         ItemCount := GetMenuItemCount(Menu);         for I := 0 to ItemCount - 1 do           EnableMenuItem(Menu, GetMenuItemID(Menu, I), MF_DISABLED or MF_GRAYED);         UnhookWindowsHookEx(HookHandle);         HookHandle := 0;       end;       $01E2: // это типа заставляем реагировать на WM_MENUSELECT до появления окна...          SendMessage(LPARAM.HWND, $1E5, 0, 0);     end;   MsgProc := CallNextHookEx(HookHandle, Code, WPARAM, DWORD(LPARAM)); end; procedure TForm1.WMContextMenu(var Message: TWMContextMenu); begin   if HookHandle <> 0 then UnhookWindowsHookEx(HookHandle);   HookHandle := SetWindowsHookEx(WH_CALLWNDPROC, @MsgProc, 0, GetCurrentThreadId); end; end.  | 
    
| 
         
         
         
          
           Сообщ.
           #6
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Я и сам потом понял, что поспешил с выводами. Все-таки не надо забывать про подпись Song'а   Вот еще вариант ![]() ![]() unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,   Dialogs, StdCtrls; type   TForm1 = class(TForm)     Edit1: TEdit;     procedure FormCreate(Sender: TObject);   private     { Private declarations }   public     { Public declarations }   end; var   Form1: TForm1; implementation {$R *.dfm} var  fb:boolean=true; function NewEditProc(wnd:HWND; uMsg:UINT; wParam:WPARAM; lParam:LPARAM):integer; stdcall; const  MN_SELECTITEM = $1E5; begin  case uMsg of  WM_ENTERIDLE: if (wParam=MSGF_MENU) and fb then                begin SendMessage(lParam, MN_SELECTITEM, 0, 0); fb:=false end;  WM_MENUSELECT:       begin         if (lParam=0) and (HIWORD(DWORD(wParam))=word(-1)) then fb:=true else         if fb then         begin          // извращаемся над меню            EnableMenuItem(lParam, GetMenuItemID(lParam, 2), MF_DISABLED or MF_GRAYED);          DeleteMenu(lParam,1,MF_BYPOSITION);          DeleteMenu(lParam,5,MF_BYPOSITION);         end       end;  end;    result:=CallWindowProc(Pointer(GetWindowLong(wnd,GWL_USERDATA)),wnd,uMsg,wParam,lParam) end; procedure TForm1.FormCreate(Sender: TObject); begin  SetWindowLong(Edit1.Handle,GWL_USERDATA,SetWindowLong(Edit1.Handle, GWL_WNDPROC, LPARAM(@NewEditProc))) end; end.  | 
    
| 
         
         
         
          
           Сообщ.
           #7
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Krid @  WM_ENTERIDLE: if (wParam=MSGF_MENU) and fb then begin SendMessage(lParam, MN_SELECTITEM, 0, 0); fb:=false end; во-во, это как раз та ж, о которой я так недавно говорил     | 
    
| 
         
         
         
          
           Сообщ.
           #8
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Она самая   
        
      ![]() Это окно можно еще WinEventHook'ом достать, но это еще бОльшая ж.     | 
    
| 
         
         
         
          
           Сообщ.
           #9
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Спасибо за помощь, значит, я в правильном направлении думал (WM_CONTEXTMENU). Работает, второй вариант ещё не пробовал. Ещё вопрос насчёт $01E2 - что это, в Messages такого нет?  
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #10
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          А не подскажите как отследить движение мышки на компоненте PopupMenu? Интересует именно то, что нужно узнать над каким Item' ом он находится, т.к. у Item' ов нет свойства OnMouseMove.   
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #11
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Перехват сообщения WM_MENUSELECT (проще через хук как в #5), плюс код определения MenuItem по ItemID - можно взять из исходника TPopupList.WndProc в модуле menus.pas   
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #12
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата leo @  Перехват сообщения WM_MENUSELECT (проще через хук как в #5), плюс код определения MenuItem по ItemID - можно взять из исходника TPopupList.WndProc в модуле menus.pas Есть небольшой опыт, но он почему-то работает только с MainMenu, В чём проблема может быть? ![]() ![]() unit main; interface uses    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,    Dialogs, Menus, StdCtrls; type    TForm1 = class(TForm)      lbl1: TLabel;      suiPopupMenu1: TsuiPopupMenu;    private      procedure WmMenuSelect (var Message: TMessage); message WM_MENUSELECT;    end; var    Form1: TForm1; implementation {$R *.dfm} { TForm1 } procedure TForm1.WmMenuSelect(var Message: TMessage); var    Item: TMenuItem;    I: Integer; begin    Item := suiPopyupMenu1.FindItem(Message.LParam, fkHandle);    if Assigned(Item) then      for I := 0 to Item.Count - 1 do        if Item.Items[I].Command = Message.WParamLo then          lbl1.Caption:= Item.Items[I].Caption); //Записываем выбранный Item end; end.  | 
    
| 
         
         
         
          
           Сообщ.
           #13
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата eclipse_99 @  В чём проблема может быть? В том, что родительским окном для всех PopupMenu является не форма, а PopupList.Window. Поэтому нужно либо подменять его WndProc через SetWindowLong, либо проще - использовать хук SetWindowHookEx  | 
    
| 
         
         
         
          
           Сообщ.
           #14
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Код в #5\WM_CONTEXTMENU не работает при первом ПКМ на TEdit.  
        
      Но работает при ПКМ на самой форме. Delphi XE3...  | 
    
| 
         
         
         
          
           Сообщ.
           #15
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата BugMeNot @  Код в #5\WM_CONTEXTMENU  Зачем тебе вообще WM_CONTEXTMENU? С ним такая же проблема, как и WM_MENUSELECT - шлется родительскому окну меню, которое не обязано быть именно формой. Можно просто установить хук в FormCreate и снять в FormDestroy, а "включать\выключать" его установкой доп.глобальной переменной HookOn:boolean - если установлена, то что-то делаешь в процедуре хука, если нет, то сразу вызываешь CallNextHookEx  |