Unsolved QTreeView and Qt::ItemIsAutoTristate
-
I've spent a while now, faffing with the
QTreeView
and theQt::ItemIsAutoTristate
flag to try and get parent/child tree items to check/uncheck/partially check where applicable.Can anyone point me towards a working solution for this, please?
I have a mostly-working
QAbstractItemModel
implementation (code base is too large to post) however, the final piece to the puzzle is getting these checkboxes to work in a tri-state fashion.Things I have done so far in the custom
QAbstractItemModel
class:- ORed in the
Qt::ItemIsAutoTristate
flag together with theQt::ItemIsUserCheckable
flag in theflags
function - Overridden the
hasChildren
function, returningtrue
/false
where applicable - Overridden the
data
function and return the correctQt::CheckState
value
I've now run out of ideas. Googling doesn't prove to be particularly useful either.
Any help would be mahoosively appreciated! Thanks.
- ORed in the
-
a few questions:
- what version of Qt are you using?
- Are you subclassing the model just to implement this or do you have other needs?
- When your custom model emits
dataChanged
does it (or could it) pass the 3rd argument?
-
@VRonin thanks for replying.
I'm currently running Qt 5.10.1 however there is no reason why I cannot change to the latest.
I am subclassing the
model
to satisfy other needs.At the moment,
dataChanged
only emits two arguments however I see no reason why I could not emit a third argument. What would the 3rd argument be useful for? -
So please provide a simple testcase - a simple data() and setData() function with only the checkbox stuff will help to see what's going wrong. It does work for me.
-
@Christian-Ehrlicher Are you using a
QTreeView
or aQTreeWidget
?Since I posted this question, I did a bit of digging around the
qtreeview.cpp
source files and there was little mention of anythingcheckbox
ortristate
related so I'm actually wondering whether this auto-tristate feature is supported out-the-box.I'll try and post some code shortly...
-
I don't see why QTreeView should somehow mention the QCheckBox at all. The only this QTreeView has to do (and which is done in QAbstractItemView) is to properly pas the Qt::CheckState role to the delegate and handle the click.
-
@Christian-Ehrlicher sorry, maybe I should have said that there was no mention of
CheckState
rather thancheckbox
as I appreciate that theQTreeView
would not need any reference to this. -
Ok, so I've taken the
editabletreemodel
example project and I've made the following changes to support checkboxes:treeitem.h
:- Added a
Qt::CheckState checked
field to theprivate
members - Changed the
data
function signature toQVariant data(int column, int role) const
- Changed the
setData
function signature tobool setData(int column, const QVariant &value, int role)
treeitem.cpp
:- Altered the
data
andsetData
functions as follows:
QVariant TreeItem::data(int column, int role) const { if (role == Qt::CheckStateRole) { if (column == 0) { return checked; } else { return QVariant(); } } return itemData.value(column); } bool TreeItem::setData(int column, const QVariant &value, int role) { if (column < 0 || column >= itemData.size()) return false; if ((column == 0) && (role == Qt::CheckStateRole)) { checked = (Qt::CheckState)value.toUInt(); return true; } itemData[column] = value; return true; }
treemodel.cpp
:- Updated all references to
data
orsetData
, adding in therole
parameter except insetupModelData
whereQt::EditRole
is passed as the 3rd argument - Altered the
flags
,data
andsetData
functions as follows:
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; return Qt::ItemIsEditable | QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate; } QVariant TreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::CheckStateRole) return QVariant(); TreeItem *item = getItem(index); return item->data(index.column(), role); } bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role != Qt::EditRole && role != Qt::CheckStateRole) return false; TreeItem *item = getItem(index); bool result = item->setData(index.column(), value, role); if (result) emit dataChanged(index, index, {role}); return result; }
When I run the example, I can happily check/uncheck items in the
QTreeView
however, the tristate-ness is not propagated. - Added a
-
A checkbox can either be checked or unchecked. A tri-state state can only happen programatically e.g. when the children are checked and unchecked therefore the default delegate only supports checked/unchecked. The tri-state has to be calculated by the model. See for example the implementation in QTreeWidget: https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtreewidget.cpp.html#1840
-
@Christian-Ehrlicher Ah ok, so it must be implemented programmatically.