PDA

View Full Version : Checkboxes in Treeview do not get refreshed



mesch.t
17th February 2009, 21:22
Hi!

I have a QTreeview which displays a FilesystemModel with Checkboxes before the files. If a directory gets checked and has childs, all the subitems should get checked.
The logic is working BUT the view does not get refreshed!
If I have the directory with sub-items expanded I have to collapse/expand it again to see the (correct) rendered result.
The code in question is this:


QVariant FileModel::data(const QModelIndex &index, int role) const
{
if(index.isValid() && index.column() == 0 && role == Qt::CheckStateRole) {
const QString path = this->filePath(index);
if(m_files.isEmpty()) {
return Qt::Unchecked;
}
if(m_files.contains(path)) {
return Qt::Checked;
}
if(m_excludeFiles.contains(path)) {
return Qt::Unchecked;
}
if(parentIsExcluded(path)) {
return Qt::Unchecked;
}
if(parentIsChecked(path)){
return Qt::Checked;
}
return Qt::Unchecked;
}
return QFileSystemModel::data(index, role);
}


The flags method returns
defaultFlags |= Qt::ItemIsUserCheckable;
setData just fills my QSets (m_files, m_excludeFiles) and returns true or calls QFileSystemModel::setData(index, value, role);

What am I missing?
Thank you very much

m.

wysota
17th February 2009, 23:49
This is not the way to go because of at least two reasons. One is that you don't allow the user to uncheck any of the boxes (unless that's what you want) because the checkbox state is unrelated to any of the user's actions. The other is that you didn't inform the views that data of the model has changed. You need to emit dataChanged() signal for the range of indexes that had their data (like the check state) changed and the signal should be emitted each time you change m_files, m_excludeFiles or anything that might make parentIsExcluded() or parentIsChecked() change return values for the same indexes.

mesch.t
18th February 2009, 07:51
Thank you for your response -

The user is able to change the state of the checkboxes:


bool FileModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if(index.isValid() && index.column() == 0 && role == Qt::CheckStateRole) {
QString path = filePath(index);
if(value.toInt() == Qt::Checked) {
m_files.insert(path);
m_excludeFiles.remove(path);
} else {
if(parentIsChecked(path)) {
m_excludeFiles.insert(path);
} else {
m_files.remove(path);
}
}
emit dataChanged(index, index); // here I have to check if how many items are visible to inform the view???
return true;
}
return QFileSystemModel::setData(index, value, role);
}


My first try to accomplish this "check-the-files-in-subfolders-automatically" was quite as you suggested:
I checked every Item recursively and therefore knew all the indexes that changed and could emit the dataChanged-signal - but performance was of course very low - especially if you checked a very top-level directory.
So I thought about it and came to the following conclusion:
All files are treated recursively (all of their content is included or excluded) and depend solely on their parent item (or itself when clicked)

And so I thought that if I return the correct state in the ::data method it is enough.
The function gets called and if I add debug output I can see it returns the correct values - but I have to move the mouse over the items or collapse/expand to see the end result.

Is there a way to refresh all the visible items or do I have to think of another way to achive the desired behaviour described above?

Thanks!

wysota
18th February 2009, 13:01
You can try emitting layoutChanged() for the most parent item instead of dataChanged() for subitems.

mesch.t
18th February 2009, 14:07
Yes!
That did it and it's fast!
Thank you!

phamtv
13th April 2011, 20:53
mesch.t, I am trying to resolve the same issue you have encounter in this thread. Can you provide some code snippet for your solution? Thanks!