QT 从文件和文件夹列表中选择多项

QT Multiple item selection from a list of files and folders

我正在 Unix 中开发 Qt C++ 应用程序,我一直在尝试做类似于此图所示的事情:

如您所见,有一个文件和文件夹列表,用户可以 select 多个(如果一个文件夹是 selected,所有子项也会 select编)。我真的不在乎 folder/file 图标是否显示。

我能够创建一个 QDir 列表,它存储给定根路径的所有文件和文件夹路径。问题是我真的不知道使用哪些小部件来设计 selection 面板。

顺便说一句,QDir的lis是一个向量,但可以很容易地修改成其他任何东西。

谢谢!

您可能需要考虑 QTreeWidget,或者它是更高级的版本 - QTreeView 和适当的数据模型。

您可以尝试为QFileSystemModel, override flags() with Qt::ItemIsUserCheckable, override setData() and apply the model to QTreeView. Full example can be found at https://github.com/em2er/filesysmodel制作代理模型。这段代码只是一个概念,我还没有对它进行彻底的测试,但是你可以从中得到一些想法。它看起来像屏幕截图上的样子:

您也可以将它与 Merged Proxy Model 结合使用,以在一个视图中显示多个起始路径。

正如一些用户所建议的,我最终使用了 QFileSystemModel。我将完整描述我是如何实现它的,以防其他人遇到这个问题并需要明确的回应。

首先,QFileSystemModel 是一个没有复选框的文件树,要添加它们,一个新的 class 扩展 QFileSystemModel 并且必须覆盖至少 3 个方法。

class FileSelector : public QFileSystemModel
{
public:
    FileSelector(const char *rootPath, QObject *parent = nullptr);
    ~FileSelector();

    bool setData(const QModelIndex& index, const QVariant& value, int role);
    Qt::ItemFlags flags(const QModelIndex& index) const;
    QVariant data(const QModelIndex& index, int role) const;

private:
    QObject *parent_;
    /* checklist_ stores all the elements which have been marked as checked */
    QSet<QPersistentModelIndex> checklist_;
};

创建模型时必须设置一个标志,以指示它应该有一个可检查的框。这就是我们将使用 flags 函数的原因:

Qt::ItemFlags FileSelector::flags(const QModelIndex& index) const
{
    return QFileSystemModel::flags(index) | Qt::ItemIsUserCheckable;
}

当在复选框中单击时,将调用方法 setData,并使用被单击元素的索引(不是复选框本身,而是 :

bool FileSelector::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (role == Qt::CheckStateRole && index.column() == 0) {
        QModelIndexList list;
        getAllChildren(index, list); // this function gets all children 
        // given the index and saves them into list (also saves index in the head)
        if(value == Qt::Checked)
        {
            for(int i = 0; i < list.size(); i++)
            {
               checklist_.insert(list[i]);
               // signals that a change has been made
               emit dataChanged(list[i], list[i]);
            }
        }
        else if(value == Qt::Unchecked)
        {
            for(int i = 0; i < list.size(); i++)
            {
                checklist_.remove(list[i]);
                emit dataChanged(list[i], list[i]);
            }
        }
        return true;
    }
    return QFileSystemModel::setData(index, value, role);
}

dataChanged 发出信号或您打开树的新路径时,将调用data 函数。在这里你必须确保只在第一列(文件名旁边)显示复选框,并检索复选框的状态,将其标记为 checked/unchecked.

QVariant FileSelector::data(const QModelIndex& index, int role) const
{
    if (role == Qt::CheckStateRole && index.column() == 0) {
        if(checklist_.contains(index)) return Qt::Checked;
        else return Qt::Unchecked;
    }
    return QFileSystemModel::data(index, role);
}

我唯一无法完成的事情是获取所有子项,因为必须打开文件夹才能检索子项。因此,关闭的文件夹在您打开之前不会有任何子文件夹。

希望这可以帮助到和我有同样问题的人!