Показать стандартное меню правой кнопкой мыши - Delphi - PullRequest
8 голосов
/ 12 марта 2011

У меня есть список, который содержит список файлов.Могу ли я получить доступ к контекстному меню Windows в списке для доступа к элементам открытия, свойств, удаления и переименования?

Ответы [ 4 ]

9 голосов
/ 12 марта 2011

Kermia проверяет модуль JclShell из библиотеки JEDI JCL, внутри этого модуля существует функция с именем DisplayContextMenu, которая показывает контекстное меню, связанное с файлом. эта функция инкапсулирует вызовы интерфейса IContextMenu и упрощает вашу работу.

function DisplayContextMenu(const Handle: HWND; const FileName: string;
  Pos: TPoint): Boolean;
5 голосов
/ 12 марта 2011

Проверьте интерфейс IContextMenu . Но имейте в виду, что оболочка Windows не идентифицирует свои объекты по имени файла - фактически они не могут быть файлами. Он использует конкатенацию идентификаторов, и вам может потребоваться узнать, к какому списку идентификаторов элементов назначен файл, прежде чем вызывать некоторые функции оболочки для него.

3 голосов
/ 13 марта 2011

Вот пример реализации, использующий событие OnContextPopup списка, который заполняется именами файлов в каталоге проекта, для запуска контекстного меню файла при щелчке правой кнопкой мыши по его имени:

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1ContextPopup(Sender: TObject; MousePos: TPoint;
      var Handled: Boolean);
  private
  protected
    procedure WndProc(var Msg: TMessage); override;
  public
  end;

var
  Form1: TForm1;

implementation

uses
  shlobj, comobj;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  SearchRec: TSearchRec;
begin
  ListBox1.Clear;

  // populate list box with files in the project folder
  if FindFirst(ExtractFilePath(Application.ExeName) + '*.*',
               0, SearchRec) = 0 then
    repeat
      ListBox1.Items.Add(SearchRec.Name);
    until FindNext(SearchRec) <> 0;
  FindClose(SearchRec);
end;

var
  // Required to handle messages for owner drawn items, as in 'SendTo' menu.
  // Also used as a flag in WndProc to know if we're tracking a shortcut menu.
  ContextMenu2: IContextMenu2 = nil;

procedure TForm1.ListBox1ContextPopup(Sender: TObject; MousePos: TPoint;
  var Handled: Boolean);
var
  Item: Integer;
  DeskFolder, Folder: IShellFolder;
  Eaten, Attributes: ULONG;
  pIdl, FolderpIdl: PItemIDList;
  ContextMenu: IContextMenu;
  Menu: HMENU;
  Pos: TPoint;
  Cmd: DWORD;
  CommandInfo: TCMInvokeCommandInfo;
begin
  Item := (Sender as TListBox).ItemAtPos(MousePos, True);
  Handled := Item <> -1;
  if not Handled then
    Exit;
  TListBox(Sender).ItemIndex := Item;

  // IShellFolder for Desktop folder (root)
  OleCheck(SHGetDesktopFolder(DeskFolder));

  // Item ID List for the folder that the file is in
  Attributes := 0;
  OleCheck(DeskFolder.ParseDisplayName(Handle, nil,
                    PWideChar(WideString(ExtractFilePath(Application.ExeName))),
                    Eaten, FolderpIdl, Attributes));

  // IShellFolder for the folder the file is in
  OleCheck(DeskFolder.BindToObject(FolderpIdl, nil, IID_IShellFolder, Folder));
  CoTaskMemFree(FolderpIdl);

  // Item ID List for the file, relative to the folder it is in
  Attributes := 0;
  OleCheck(Folder.ParseDisplayName(Handle, nil,
           PWideChar(WideString(ExtractFileName(TListBox(Sender).Items[Item]))),
           Eaten, pIdl, Attributes));

  // IContextMenu for the relative Item ID List
  OleCheck(Folder.GetUIObjectOf(Handle, 1, pIdl, IID_IContextMenu,
                                  nil, ContextMenu));
  CoTaskMemFree(pIdl);

  Menu := CreatePopupMenu;
  try
    // Populate our menu with shortcut items
    OleCheck(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE));

    // ContextMenu2 used in WndProc
    ContextMenu.QueryInterface(IID_IContextMenu2, ContextMenu2);
    try
      Pos := TWinControl(Sender).ClientToScreen(MousePos);
      // launch the menu
      Bool(Cmd) := TrackPopupMenu(Menu,
                            TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD,
                            Pos.X, Pos.Y, 0, Handle, nil);
    finally
      // clear so that we don't intervene every owner drawn menu item message in
      // WndProc
      ContextMenu2 := nil;
    end;

    // Invoke command if we have one
    if Bool(Cmd) then begin
      FillChar(CommandInfo, SizeOf(CommandInfo), 0);
      CommandInfo.cbSize := SizeOf(CommandInfo);
      CommandInfo.hwnd := Handle;
      CommandInfo.lpVerb := MakeIntResource(Cmd - 1);
      CommandInfo.nShow := SW_SHOWNORMAL;

      OleCheck(ContextMenu.InvokeCommand(CommandInfo));
    end;

  finally
    DestroyMenu(Menu);
  end;
end;

procedure TForm1.WndProc(var Msg: TMessage);
begin
  if ((Msg.Msg = WM_INITMENUPOPUP) or (Msg.Msg = WM_DRAWITEM)
              or (Msg.Msg = WM_MEASUREITEM)) and Assigned(ContextMenu2) then
    ContextMenu2.HandleMenuMsg(Msg.Msg, Msg.WParam, Msg.LParam)
  else
    inherited;
end;
2 голосов
/ 12 марта 2011

Я бы порекомендовал взглянуть на что-то вроде tpShellShock , когда вы хотите отобразить элементы управления, подобные оболочке, в вашем приложении Delphi. Он предлагает древовидные представления, представления списков и т. Д., Которые можно соединять вместе, как в Windows Explorer. Он будет отображать соответствующие значки для файлов. Я уверен, что он также предлагает возможности, о которых вы говорите.

Может потребоваться некоторая работа по переносу, если вы работаете на современном Unicode Delphi, но когда я это сделал, это оказалось относительно простым.

Нет сомнений, что есть другие библиотеки, которые предлагают элементы управления оболочкой, это только та, с которой я знаком.

В противном случае, если вы хотите придерживаться текущего решения, проще всего реализовать собственные действия в меню. Open и Properties - это просто вызов ShellExecute с соответствующим глаголом. Удалить - это вызов DeleteFile, а Rename - это вызов MoveFile.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...