TypechoJoeTheme

鱼一的博客 ◡̈

yuyi

知不可乎骤得,托遗响于悲风
网站页面
标签搜索
c++

`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 functionBroken 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。

赞(0)
版权属于:

鱼一的博客 ◡̈

本文链接:

https://yuyi.monster/archives/221/(转载时请注明本文出处及文章链接)

评论 (0)

More Info for me 📱

IP信息

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月