#include "contextmenu.h"
#include "shellitem.h"
#include <QString>
#include <QStringList>
#include <QFileInfo>
#include <QPoint>
#include <Shlobj.h>
#include <shlwapi.h>
#include <windows.h>
struct ContextMenuHelper
{
static ContextMenuHelper* Instatnce()
{
static ContextMenuHelper helper;
return &helper;
}
~ContextMenuHelper()
{
if(pDesktop)
pDesktop->Release();
}
bool isRootPath(QString const& path)
{
//for dirver D: D:/
//for virtual driver, the path's len is larger than 3
return path.size() > 1 && path.size() <= 3;
}
void showContextMenu(QStringList const& fileNames, void* handle, int x, int y)
{
QString parentPath = toWindowsPath(QFileInfo(fileNames[0]).path());
LPSHELLFOLDER pParentFolder = getParentFolder(parentPath, isRootPath(fileNames[0]));
if(!pParentFolder)
return;
LPITEMIDLIST* pidlFiles = (LPITEMIDLIST *)malloc(sizeof(LPITEMIDLIST) * fileNames.size());
{
LPENUMIDLIST pEnum;
HRESULT hr = pParentFolder->EnumObjects(0, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnum);
if(SUCCEEDED(hr))
{
LPITEMIDLIST pidl;
STRRET str;
int index = 0;
while(pEnum->Next(1, &pidl, 0) == S_OK)
{
pParentFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
QString fileName = toLinuxPath(strToString(pidl, &str));
if(!fileNames.contains(fileName))
CoTaskMemFree(pidl);
else
{
if(index < fileNames.size())
pidlFiles[index++] = pidl;
}
}
}
}
IContextMenu *pcm;
HRESULT hr = pParentFolder->GetUIObjectOf(0,
fileNames.size(),
(PCUITEMID_CHILD_ARRAY)pidlFiles,
IID_IContextMenu,
0,
(LPVOID*)&pcm);
if(SUCCEEDED(hr))
{
HMENU hPopup = CreatePopupMenu();
if(hPopup)
{
hr = pcm->QueryContextMenu(hPopup, 0, 1, 0x7fff, CMF_NORMAL);
if(SUCCEEDED(hr))
{
IContextMenu2 *pcm2;
pcm->QueryInterface(IID_IContextMenu2, (LPVOID*)&pcm2);
UINT idCmd;
idCmd = TrackPopupMenu( hPopup,
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
x,
y,
0,
(HWND)handle,
0);
if(pcm2)
{
pcm2->Release();
pcm2 = NULL;
}
if(idCmd && (idCmd != (UINT)-1))
{
CMINVOKECOMMANDINFO cmi;
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = 0;
cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - 1);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
pcm->InvokeCommand(&cmi);
}
}
DestroyMenu(hPopup);
}
}
for(int i = 0; i < fileNames.size(); i++)
ILFree(pidlFiles[i]);
free(pidlFiles);
pParentFolder->Release();
}
LPSHELLFOLDER getParentFolder(QString const& filePath, bool isRoot = false)
{
LPSHELLFOLDER pDrives = getSpecialFolder(CSIDL_DRIVES);
ShellItem::Ptr item;
if(pDrives)
{
LPENUMIDLIST pEnum;
HRESULT hr = pDrives->EnumObjects(0, SHCONTF_FOLDERS, &pEnum);
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidl;
STRRET str;
QString childPath;
while(pEnum->Next(1, &pidl, 0) == S_OK)
{
pDrives->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
childPath = strToString(pidl, &str);
if(isRootPath(childPath) && filePath.startsWith(childPath))
{
item = ShellItem::Ptr(new ShellItem());
item->pidlRel = pidl;
pDrives->AddRef();
item->pParentFolder = pDrives;
break;
}
}
while(true)
{
if(childPath == filePath)
break;
if(!getChildParent(item, childPath, filePath))
break;
}
pEnum->Release();
if(item)
{
if(isRoot)
return item->pParentFolder;
LPSHELLFOLDER pParentFolder = 0;
item->pParentFolder->BindToObject(item->pidlRel, 0, IID_IShellFolder,
(LPVOID*)&pParentFolder);
return pParentFolder;
}
}
}
return 0;
}
bool getChildParent(ShellItem::Ptr & item, QString &childPath, QString const& filePath)
{
if(!item)
return false;
LPSHELLFOLDER pParentFolder = NULL;
HRESULT hr = item->pParentFolder->BindToObject(item->pidlRel, 0, IID_IShellFolder,
(LPVOID*)&pParentFolder);
if(SUCCEEDED(hr))
{
LPENUMIDLIST pEnum;
hr = pParentFolder->EnumObjects(NULL, SHCONTF_FOLDERS, &pEnum);
if(SUCCEEDED(hr))
{
LPITEMIDLIST pidl;
DWORD dwFetched = 1;
STRRET str;
while(S_OK == (pEnum->Next(1, &pidl, &dwFetched)) && dwFetched)
{
pParentFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
childPath = strToString(pidl, &str);
int index = filePath.indexOf(childPath);
if(index >= 0)
{
if(filePath == childPath || filePath.at(childPath.size()) == '\\')
{
ShellItem::Ptr newItem(new ShellItem());
newItem->pidlRel = pidl;
pParentFolder->AddRef();
newItem->pParentFolder = pParentFolder;
item = newItem;
pEnum->Release();
pParentFolder->Release();
return true;
}
}
}
pEnum->Release();
}
pParentFolder->Release();
}
return false;
}
LPSHELLFOLDER getSpecialFolder(int idFolder)
{
LPITEMIDLIST pidl;
LPSHELLFOLDER psf = NULL;
HRESULT hr = SHGetSpecialFolderLocation(0, idFolder, &pidl);
Qt下显示文件及目录的Windows右键菜单
需积分: 0 65 浏览量
更新于2024-03-05
收藏 10KB ZIP 举报
在Windows操作系统中,右键菜单是用户与文件和目录交互的重要方式之一,它提供了快捷的操作选项。使用Qt库,开发者可以创建自定义的右键菜单,以增强应用程序的功能或提供特定的操作。本资源是一个Qt工程实例,专注于在Windows环境下为文件和目录添加自定义的右键菜单。
我们要理解Qt库中的`QContextMenuEvent`类,这是处理鼠标右键点击事件的关键。当用户在窗口或控件上右击时,这个事件会被触发。通过重写`QObject`或`QWidget`的`contextMenuPolicy()`方法,可以设置默认的上下文菜单策略,比如返回`Qt::CustomContextMenu`,这将允许我们自定义右键菜单。
接着,我们需要实现`customContextMenuRequested(const QPoint &pos)`信号的槽函数。这个信号会在用户请求上下文菜单时被发射,通常是在`contextMenuPolicy()`返回`Qt::CustomContextMenu`的情况下。在槽函数中,我们可以创建并显示`QMenu`对象,这个菜单将包含我们的自定义选项。
创建`QMenu`后,可以通过`addAction()`方法添加菜单项。`QAction`对象代表菜单中的一个选项,它可以关联到一个槽函数,这样当用户选择该菜单项时,对应的函数就会被执行。例如,我们可以添加一个“打开”动作,关联到`QDesktopServices::openUrl()`,用于打开选中的文件或目录。
对于Windows系统,可能需要使用API函数来获取和操作文件和目录。Qt库提供了`QWinExtras`模块,其中的`QWinContext`类可以访问Windows API。例如,获取当前选中的文件或目录信息,可以使用`QWinContext::shellItemFromPoint()`函数。
在实际项目中,为了兼容不同类型的文件和目录,我们需要对每个菜单项的动作进行条件判断。例如,如果用户右键点击的是一个文件,我们可以添加打开、复制、重命名等选项;如果是目录,则可以添加浏览、新建文件夹等操作。
在实现这些功能时,确保考虑到错误处理和用户体验。例如,当用户尝试打开不存在的文件或没有权限操作时,应显示适当的错误消息。同时,保持菜单简洁,避免过多的选项使用户感到困惑。
为了使这个Qt工程能在Windows下正常工作,我们需要确保所有必要的库和依赖都已正确配置。这包括Qt库本身,以及任何使用到的额外模块如`QWinExtras`。在编译和运行项目时,确保Qt的环境变量已经设置好,并且编译器支持Windows API调用。
这个Qt工程实例展示了如何利用Qt和Windows API创建自定义的文件和目录右键菜单,提供了增强用户交互的一种方法。开发者可以根据自己的需求扩展和修改这个示例,以适应各种应用场景。