yuyi
`QFileSystemModel::mkdir()` 在UI界面文件创建踩坑
修复 QFileSystemModel::mkdir()
中的崩溃问题 🔧
在使用 Qt5 的 QFileSystemModel 替换Qt4中的 QDirmodel 中的文件创建方法时遇到问题。
初步检查 🕵️♂️
在点击创建文件后,如果不输入新建文件名并点击确认,崩溃就不会发生。因此,首先排除了下面右键菜单代码的问题
void MainWindow::showLocalTreeViewMenu(const QPoint &pos)
{
QMenu* menu=new QMenu(this);
menu->addAction(QString(tr("新建文件夹")),this,SLOT(mkdir()));
menu->addAction(QString(tr("删除")),this,SLOT(rm()));
menu->addAction(QString(tr("刷新")),this,SLOT(localDirRefresh()));
menu->exec(QCursor::pos());
}
接着通过 qDebug() 打印信息,确认了崩溃发生前最后执行的地方。
打印信息如下
19:51:29: Starting /Users/yuyy/build-Kakaxi-Replacement_for_Desktop_Qt_5_15_2_clang_64bit-Debug/Kakaxi.app/Contents/MacOS/Kakaxi...
Directory loaded: "/Users/yuyy/build-Kakaxi-Replacement_for_Desktop_Qt_5_15_2_clang_64bit-Debug/Kakaxi.app/Contents/MacOS"
2024-04-19 19:51:34.873 Kakaxi[86489:1284416] TSM AdjustCapsLockLEDForKeyTransitionHandling - _ISSetPhysicalKeyboardCapsLockLED Inhibit
index: QModelIndex(0,1,0x60000348d4d0,QSortFilterProxyModel(0x6000005adbc0))
dirName::::
4 ---- "1234"
4 ---- "1234"
Empty filename passed to function
Broken filename passed to function
1111111111
3333
19:53:15: /Users/yuyy/build-Kakaxi-Replacement_for_Desktop_Qt_5_15_2_clang_64bit-Debug/Kakaxi.app/Contents/MacOS/Kakaxi 崩溃。
结合崩溃信息Empty filename passed to function
和 Broken filename passed to function
, 可以发现是与文件索引路径有关。接着验证 QModelIndex newDirIndex = dirModel->mkdir(index, dirName);
文件创建代码中的 dirModel 和 index 是否有问题。
QModelIndex mkdir(const QModelIndex &parent, const QString &name);
下面代码并没有被触发,说明 dirModel 和 index 都有值
if (!index.isValid()) {
qDebug() << "Invalid index, cannot create directory";
return;
}
if (!dirModel) {
qDebug() << "The specified index does not point to a directory.";
return;
}
尝试使用代码 qDebug() << "问题似乎在这里" << dirModel->filePath(index)
打印 index 路径
有时会直接崩溃,有时会先打印如下信息,接着在 mkdir 方法处崩溃。
The file path for the index is: "\u0000/\u0000/\u0000/\u0000/\u0000/\u0000/\u0000/\u0000\u0000"
深入诊断 🔍
怀疑 QFileSystemModel
对象 dirModel
是否有效,使用下面方法进行验证。
首先检查 dirModel 是否有效,成功运行 qDebug() << "打印信息:" << dirModel->rootPath();
代码,且打印出的文件路径没有问题。
接着手动创建一个合法路径尝试新建文件夹操作
// 假设你有一个有效的文件路径
QString filePathtt = "/xxx/Contents/MacOS/dir1";
// 获取 QModelIndex
const QModelIndex indextt = dirModel->index(filePathtt);
传入 QModelIndex newDirIndex = dirModel->mkdir(indextt, "dirName")
发现文件夹创建成功
-rw-r--r-- 1 yuyy staff 43 4 19 19:00 1.txt
drwxr-xr-x 2 yuyy staff 64 4 19 23:01 dirName
由此判断大概率是 QModelIndex 类型的文件路径索引出了问题。
尝试使用代码打印 index 对象和手动创建的对象 indextt 的信息
parentIndex = index.parent();
if (index.isValid()) {
qDebug() << "Row:" << index.row()
<< "Column:" << index.column()
<< "Data:" << index.data().toString()
<< "Parent Row:" << index.parent().row()
<< "Parent Data:" << parentIndex.data().toString();
} else {
qDebug() << "Current index is not valid.";
}
终端显示信息如下,且有时候 index
对象会显示的 Data: --
和 Data: Folder
, 也有时会正确显示 `Data: dir1
Row: 0 Column: 2 Data: "Folder" Parent Row: 0 Parent Data: "MacOS" # idnex 打印信息
Row: 0 Column: 0 Data: "dir1" Parent Row: 0 Parent Data: "MacOS" # indextt 打印信息
确定问题根源 🎯
这说明 QModelIndex index = ui->treeView->currentIndex();
获取索引路径的方式有问题。
修改为指定文件名的索引路径
QModelIndex currentIndex = ui->treeView->currentIndex();
QModelIndex indexs = currentIndex.sibling(currentIndex.row(), 0);
接着以为万事大吉,再次运行!继续崩溃。
检查打印信息,发现 index 的信息没有任何问题。
后面仔细发现由于使用了 QSortFilterProxyModel 作为代理来进行排序或过滤,所以 ui->treeView->currentIndex() 返回的 QModelIndex 实际上是属于代理模型的,而不是原始的 QFileSystemModel。
在 dirModel 中使用这个索引,你需要将其从代理模型的索引转换为原始模型的索引。
在使用 QTreeView 和 QSortFilterProxyModel 时遇到索引不匹配原始模型的问题
使用 mapToSource 方法
你需要使用 QSortFilterProxyModel 的 mapToSource() 方法将代理模型的索引转换为源模型(QFileSystemModel)的索引。这样你才能在 dirModel 中正确使用这个索引。
QModelIndex currentIndex = ui->treeView->currentIndex();
QModelIndex indexs = currentIndex.sibling(currentIndex.row(), 0); // 0是文件名列
qDebug() << "indexs";
if (!proxyModel) {
qDebug() << "proxyModel is not initialized";
return;
}
QModelIndex index = proxyModel->mapToSource(indexs);
注意事项 📌
另外需要注意的是,在前面创建代理模型时,在成员变量里声明后,不要重复使用 QSortFilterProxyModel proxyModel = new QSortFilterProxyModel(this);
来赋值
局部变量还是成员变量:在你的问题中,如果你是这样声明的:
Copy code
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
并且这条语句出现在成员函数内部,而不是在类构造函数或其他方法中初始化成员变量时,它只会创建一个新的局部变量,不影响类的成员变量。然而,如果这条语句是:
Copy code
proxyModel = new QSortFilterProxyModel(this);
那么它将影响类的成员变量 proxyModel。