Hello,
I have a QFileSystemModel sub-class “FileSysSelectModel†connected to a QTreeView
The QTreeView shows only the file name information and each item is checkable.
Here is how the QFileSystemModel sub_class is implemented.
#ifndef FILESYSSELECTMODEL_H
#define FILESYSSELECTMODEL_H
#include<QFileSystemModel>
#include <QSet>
#include <QPersistentModelIndex>
#include <QVariant>
class FileSysSelectModel: public QFileSystemModel
{
Q_OBJECT
private:
QSet<QPersistentModelIndex> m_checkTable;
public:
int FileSysSelectModel
::columnCount(const QModelIndex &parent
) const;
virtual Qt
::ItemFlags FileSysSelectModel
::flags(const QModelIndex &index
) const;
virtual bool FileSysSelectModel
::setData(const QModelIndex &index,
const QVariant &value,
int role
);
signals:
};
#endif // FILESYSSELECTMODEL_H
#ifndef FILESYSSELECTMODEL_H
#define FILESYSSELECTMODEL_H
#include<QFileSystemModel>
#include <QSet>
#include <QPersistentModelIndex>
#include <QVariant>
class FileSysSelectModel: public QFileSystemModel
{
Q_OBJECT
private:
QSet<QPersistentModelIndex> m_checkTable;
QVariant m_noData;
public:
int FileSysSelectModel::columnCount(const QModelIndex &parent) const;
QVariant FileSysSelectModel::data(const QModelIndex &index, int role) const;
virtual Qt::ItemFlags FileSysSelectModel::flags(const QModelIndex &index) const;
virtual bool FileSysSelectModel::setData(const QModelIndex &index, const QVariant &value, int role);
signals:
void expandParentItem(const QModelIndex &index);
};
#endif // FILESYSSELECTMODEL_H
To copy to clipboard, switch view to plain text mode
#include "FileSysSelectModel.h"
//Returns columnCount=1 if columnCount >= 1, so only the name item displays.
int FileSysSelectModel
::columnCount(const QModelIndex &parent
) const {
int columns = QFileSystemModel::columnCount(parent);
return (columns >= 1)? 1 : columns;
}
//Returns the regular QFileSystemModel data or the CheckState status if required.
//All decoration has been removed from QFileSystemModel data.
{
if (role == Qt::CheckStateRole) return m_checkTable.contains(index)? Qt::Checked : Qt::Unchecked;
if (role == Qt::DecorationRole) return m_noData;
// regular QFileSystemModel case.
return QFileSystemModel::data(index, role);
}
//Sets all elements as user checkable.
Qt
::ItemFlags FileSysSelectModel
::flags(const QModelIndex &index
) const{
return QFileSystemModel::flags(index) | Qt::ItemIsUserCheckable;
}
//Sets the regular QFileSystemModel data or the CheckState status.
{
if (role == Qt::CheckStateRole)
{
std::vector<QModelIndex*> parentTable(1,&const_cast<QModelIndex&>(index));
//if the current item is in the checklist then remove it.
//if the current item is not in the checklist then add it.
if(value == Qt::Checked) m_checkTable.insert(index); else m_checkTable.remove(index);
emit dataChanged(index, index);
//Expand all the sub-items.
while (!parentTable.empty())
{
currentItem = parentTable[parentTable.size()-1];
parentTable.pop_back();
currentFirstChildItem = ¤tItem->child(0,0);
if (currentFirstChildItem->isValid())
{
emit expandParentItem(*currentItem);
int i = 0;
while(1)
{
currentChildItem = ¤tItem->child(i,0);
if (!currentChildItem->isValid()) break;
parentTable.push_back(currentChildItem);
++i;
}
}
}
return true;
}
// regular QFileSystemModel case.
return QFileSystemModel::setData(index, value, role);
}
#include "FileSysSelectModel.h"
//Returns columnCount=1 if columnCount >= 1, so only the name item displays.
int FileSysSelectModel::columnCount(const QModelIndex &parent) const
{
int columns = QFileSystemModel::columnCount(parent);
return (columns >= 1)? 1 : columns;
}
//Returns the regular QFileSystemModel data or the CheckState status if required.
//All decoration has been removed from QFileSystemModel data.
QVariant FileSysSelectModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::CheckStateRole) return m_checkTable.contains(index)? Qt::Checked : Qt::Unchecked;
if (role == Qt::DecorationRole) return m_noData;
// regular QFileSystemModel case.
return QFileSystemModel::data(index, role);
}
//Sets all elements as user checkable.
Qt::ItemFlags FileSysSelectModel::flags(const QModelIndex &index) const
{
return QFileSystemModel::flags(index) | Qt::ItemIsUserCheckable;
}
//Sets the regular QFileSystemModel data or the CheckState status.
bool FileSysSelectModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Qt::CheckStateRole)
{
QModelIndex *currentFirstChildItem;
QModelIndex *currentItem;
QModelIndex *currentChildItem;
std::vector<QModelIndex*> parentTable(1,&const_cast<QModelIndex&>(index));
//if the current item is in the checklist then remove it.
//if the current item is not in the checklist then add it.
if(value == Qt::Checked) m_checkTable.insert(index); else m_checkTable.remove(index);
emit dataChanged(index, index);
//Expand all the sub-items.
while (!parentTable.empty())
{
currentItem = parentTable[parentTable.size()-1];
parentTable.pop_back();
currentFirstChildItem = ¤tItem->child(0,0);
if (currentFirstChildItem->isValid())
{
emit expandParentItem(*currentItem);
int i = 0;
while(1)
{
currentChildItem = ¤tItem->child(i,0);
if (!currentChildItem->isValid()) break;
parentTable.push_back(currentChildItem);
++i;
}
}
}
return true;
}
// regular QFileSystemModel case.
return QFileSystemModel::setData(index, value, role);
}
To copy to clipboard, switch view to plain text mode
Here is my problem.
When I check an item, I would like the QTreeView to automatically expand all the checked item’s children (in all sub levels).
I tried to implement a mechanism in FileSysSelectModel::setData. It uses a While loop and a vector < QModelIndex* > to process and expand each item in the sub-tree under the check item.
I initialize the vector with the checked item. The While loop runs until the vector is empty. And here is what is going on inside the loop. The currently processed item is removed from the vector. If it has children, it expands it, it explores its children and it saves all ones that have children in the vector (for them to be processed on a next round).
It does not run as expected… When I check an item it only expands the first level under the checked item.
When running it with the debugger, I figured out that the all the signals that were emitted in the while loop were processed by the QTreeView slot only after the while loop terminated… That is probably where the issue is.
I need the QTreeView to check for signals for each iteration in the While loop, right?
Is a QThread the only solution for that issue?
If yes, Do I need to implement the entire QFileSystemModel instance in a sub-QThread? Or only a portion of it?
Thanks!
Bookmarks