【问题标题】:Show the default right-click menu - Delphi显示默认右键菜单 - Delphi
【发布时间】:2011-03-12 10:43:31
【问题描述】:

我有一个包含文件列表的列表框。我可以访问列表框中的 Windows 右键菜单来访问打开、属性、删除和重命名项吗?

【问题讨论】:

    标签: delphi properties menu right-click


    【解决方案1】:

    Kermia 检查 JEDI JCL 库中的 JclShell 单元,该单元内部存在一个名为 DisplayContextMenu 的函数,它显示与文件关联的上下文菜单。该函数封装了对IContextMenu接口的调用,让你的工作更轻松。

    function DisplayContextMenu(const Handle: HWND; const FileName: string;
      Pos: TPoint): Boolean;
    

    【讨论】:

    • +1 你传递什么作为 Handle 参数?它是干什么用的?
    • @David 你可以传递表单的句柄,这个句柄在IContextMenu.InvokeCommand 中使用,它接收一个CMINVOKECOMMANDINFO 结构msdn.microsoft.com/en-us/library/bb773215%28v=vs.85%29.aspx。
    • @Kernia,这个单元是 JCL(绝地代码库)的一部分。你可以从这里下载最新版本wiki.delphi-jedi.org/index.php?title=JEDI_Code_Library
    • 哇!这正是我想要的。非常感谢皮鲁兹先生。
    • @RRUZ,DisplayContextMenu() 对于一个文件来说似乎不错,但是来自不同本地驱动器的多个文件和文件夹呢?
    【解决方案2】:

    检查IContextMenu 接口。但请注意,Windows shell 不会通过文件名识别其对象——实际上它们不可能是文件。它使用 id 的串联,在调用一些 shell 函数之前,您可能需要获取文件分配到的项 id 列表。

    【讨论】:

    • 看起来它允许您枚举shell认为在上下文菜单中的内容。在我阅读时,您仍然需要自己填充菜单,然后通过此接口调用命令以响应 Delphi OnClick 事件。对吗?
    • +1 看起来确实是实现 OnClick 处理程序的好方法。
    • 是的,您必须创建菜单(至少它允许您使用您喜欢的任何类型的菜单),无论如何它会为您提供每个元素支持的命令,并让您调用正确的命令由外壳定义。它也不适用于文件,尽管这超出了用户的问题。
    【解决方案3】:

    这是一个使用列表框的“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;
    

    【讨论】:

      【解决方案4】:

      当您想在 Delphi 应用程序中显示类似 shell 的控件时,我建议您查看类似 tpShellShock 的内容。它提供了可以像资源管理器 Windows 一样连接在一起的树视图、列表视图等。它将显示文件的适当图标。我相信它也提供了你所说的设施。

      如果您使用的是现代 Unicode Delphi,可能需要进行一些移植工作,但当我这样做时,它证明相对简单。

      毫无疑问,还有其他提供 shell 控件的库,这只是我熟悉的一个。

      否则,如果您想坚持当前的解决方案,最容易实现自己的菜单操作。 Open 和 Properties 只是使用适当的动词对 ShellExecute 的简单调用。 Delete 是对 DeleteFile 的调用,而 Rename 是对 MoveFile 的调用。

      【讨论】:

        猜你喜欢
        • 2010-12-13
        • 1970-01-01
        • 2010-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多