QTreeView/QAbstractItemModel : signal "dataChanged" does not update item flags
-
Hello everybody,
I am working on a QTreeView that display five columns of Checkboxes (Policies in a Usermanagement) and those checkboxes are displayed as icons, set via a style sheet.
Which icon is displayed depends on two values:- the Data of the item (QAbstractItemModel::data())
- the Flags of the item (QAbstractItemModel::flags())
When the user clicks on one of those checkboxes, it is possible (because of a hierarchical policy-system) that not only the item clicked, but also several other items change their state. (unchecked, checked-normal, checked-grayed/inherited)
To do so, in QAbstractItemModel::setData() I change the data in the TreeItem-Class and then emit dataChanged() for the related items.The problem is that the items only aplly the changes it gets through the method data(), which is not enough to display the correct icon. The flags() are also needed, but this method does not seem to be called by the view after dataChanged is emitted. So I can see that the icons change (= my Model-Indices are correct) but they aren't displayed as they should. I have to expand/collapse any Treenode, to cause the view to update correctly (after this second action, everything is displayed as it is supposed to be)
So my question is:
Is there a way to tell the view to update the flags of specific items, from inside the model(without actually knowing the view)?P.S.:
I already thougt about misusing Qt::PartiallyChecked which would enable me to completely avoid the problem by not using flags(), but I'd prefer to use my version, because this workaround is only suitable for three states, and in the future there might come a fourth state...Here's some code-snippets from my prototype:
@QVariant CCheckBoxModel::data(const QModelIndex &index, int role) const
{
QVariant result;if (!index.isValid() || index.column() == 6)
{
return result;
}TreeItem item = static_cast<TreeItem>(index.internalPointer());
if ((role == Qt::CheckStateRole) && (index.column() != 0))
{
result = item->data(index.column());return result;
}if ((role != Qt::DisplayRole) || (index.column() != 0))
{
return QVariant();
}result = item->data(index.column());
return result;
}Qt::ItemFlags CCheckBoxModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
{
return NULL;
}TreeItem item = static_cast<TreeItem>(index.internalPointer());
if (index.column() == 0)
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
else //CheckBoxes
{
if (item->isInherited(index.column()))
{
return Qt::ItemIsSelectable;
}
else
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
}
}
}bool CCheckBoxModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || index.column() == 6)
{
return true;
}TreeItem item = static_cast<TreeItem>(index.internalPointer());
if ((role == Qt::CheckStateRole) && (index.column() != 0))
{
item->setData(index.column(), value);
emit dataChanged(index, this->index(item->childCount(), index.column(), index)); //the children might have changed too
}return true;
}@ -
Update:
The flags()-method does not seem to be the problem, the changes of the flags are applied immediately (at least the enabled state...). The problem is the style sheet:
The style sheet seems to be applied after a call to data() but before the call to flags(); at least that's what I assume after analyzing the behaviour. Or in other words: the enabled/disabled state is updated after the style sheet, which is wrong (in my case).
So I'd need a way to apply the style sheet after updating the items state.Here's my style sheet, set for the QTreeView:
@QAbstractItemView::indicator:enabled:checked
{
image: url(:cbChecked);
}QAbstractItemView::indicator:enabled:unchecked
{
image: url(:cbUnchecked);
}QAbstractItemView::indicator:disabled:checked
{
image: url(:cbGray);
}//QAbstractItemView::indicator:disabled:unchecked is not used@
btw: resetting the style with treeview->setStyleSheet(treeview->styleSheet()) in a slot connected to dataChanged() does not work
-
Next update ;)
My style sheet theory is not correct, wen I disable the style sheet completely and use the standard checkboxes, the problem is the same: enabled/disabled is "functionally" updated but not visually...
-
Ok, I solved it by not using real checkboxes at all, now I'm just returning the correct checkbox-icon in data() and nothing for CheckStateRole. I had to connect the clicked-signal from the view with an own slot in my model which implements the checkbox-behaviour...
If somebody has a better idea, Id appreciate to hear it ;)
But for now this problem is solved...