macOS下QFileIconProvider获取不存在文件图标失败求解决方案
macOS下QFileIconProvider仅用文件名获取图标问题的解决方案
给你两个可行的解决方案:
方案一:直接调用macOS原生API获取图标(Objective-C++实现)
Qt在macOS底层依赖NSWorkspace获取图标,但默认的QFileIconProvider调用的是需要全路径的iconForFile:方法,而NSWorkspace还提供了iconForFileType:方法——直接传文件扩展名就能获取对应图标,完全不用创建任何文件,完美避开路径警告。
可以用Objective-C++混写代码实现这个逻辑,直接调用原生API再转成QIcon:
#include <QIcon> #include <QtCore/qcoreapplication.h> #include <objc/message.h> #include <objc/runtime.h> QIcon getIconForFileType(const QString& extension) { // 获取NSWorkspace单例 Class nsWorkspaceClass = objc_getClass("NSWorkspace"); id sharedWorkspace = objc_msgSend(nsWorkspaceClass, sel_getUid("sharedWorkspace")); // 把QString转成NSString const char* extUtf8 = extension.toUtf8().constData(); id nsExt = objc_msgSend(objc_getClass("NSString"), sel_getUid("stringWithUTF8String:"), extUtf8); // 获取对应扩展名的图标 id nsImage = objc_msgSend(sharedWorkspace, sel_getUid("iconForFileType:"), nsExt); QIcon icon; if (nsImage) { // 取16x16尺寸的图标(可根据需求修改尺寸) id rep = objc_msgSend(nsImage, sel_getUid("bestRepresentationForRect:context:hints:"), CGRectMake(0,0,16,16), nil, nil); if (rep) { void* bitmapData = objc_msgSend(rep, sel_getUid("bitmapData")); int width = objc_msgSend(rep, sel_getUid("pixelsWide")); int height = objc_msgSend(rep, sel_getUid("pixelsHigh")); // 转成QImage再生成QIcon QImage image(static_cast<uchar*>(bitmapData), width, height, QImage::Format_ARGB32); icon = QIcon(QPixmap::fromImage(image)); } } return icon; }
使用时,从文件名里提取扩展名(比如从"test.jpg"拿到"jpg"),调用这个函数就能拿到对应图标,完全不会触发路径警告。
方案二:缓存图标像素数据,摆脱临时文件依赖
如果不想碰原生API,还是想用QFileIconProvider,可以先创建临时文件,然后把图标的像素数据提前加载到内存——因为QIcon默认是延迟加载的,直接使用的话显示时还会去读取文件,所以必须提前把pixmap提取出来,之后删掉临时文件也不会影响显示:
#include <QFileIconProvider> #include <QTemporaryDir> #include <QIcon> #include <QFile> QIcon getIconFromFileName(const QString& fileName) { QTemporaryDir tempDir; if (!tempDir.isValid()) { return QIcon(); } QString tempFilePath = tempDir.path() + "/" + fileName; // 创建空的临时文件 QFile tempFile(tempFilePath); if (!tempFile.open(QIODevice::WriteOnly)) { return QIcon(); } tempFile.close(); // 获取原始图标 QFileIconProvider provider; QIcon originalIcon = provider.icon(QFileInfo(tempFilePath)); // 提取常用尺寸的pixmap,缓存到新的QIcon里 QIcon cachedIcon; QList<int> sizes = {16,24,32,48,64}; // 按需添加需要的尺寸 for (int size : sizes) { QPixmap pixmap = originalIcon.pixmap(size, size); if (!pixmap.isNull()) { cachedIcon.addPixmap(pixmap); } } // QTemporaryDir会自动清理临时文件,无需手动删除 return cachedIcon; }
这个方案是跨平台的,不用修改平台相关代码,但需要临时创建空文件,不过QTemporaryDir会自动处理清理,不用担心残留文件。
内容的提问来源于stack exchange,提问作者MartinZ
相关产品推荐
相关产品推荐

