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);
}
我唯一无法完成的事情是获取所有子项,因为必须打开文件夹才能检索子项。因此,关闭的文件夹在您打开之前不会有任何子文件夹。
希望这可以帮助到和我有同样问题的人!
我正在 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);
}
我唯一无法完成的事情是获取所有子项,因为必须打开文件夹才能检索子项。因此,关闭的文件夹在您打开之前不会有任何子文件夹。
希望这可以帮助到和我有同样问题的人!