Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTreeView and Qt::ItemIsAutoTristate



  • I've spent a while now, faffing with the QTreeView and the Qt::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 the Qt::ItemIsUserCheckable flag in the flags function
    • Overridden the hasChildren function, returning true/false where applicable
    • Overridden the data function and return the correct Qt::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.



  • 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?


  • Qt Champions 2019

    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 a QTreeWidget?

    Since I posted this question, I did a bit of digging around the qtreeview.cpp source files and there was little mention of anything checkbox or tristate related so I'm actually wondering whether this auto-tristate feature is supported out-the-box.

    I'll try and post some code shortly...


  • Qt Champions 2019

    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 than checkbox as I appreciate that the QTreeView 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 the private members
    • Changed the data function signature to QVariant data(int column, int role) const
    • Changed the setData function signature to bool setData(int column, const QVariant &value, int role)

    treeitem.cpp:

    • Altered the data and setData 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 or setData, adding in the role parameter except in setupModelData where Qt::EditRole is passed as the 3rd argument
    • Altered the flags, data and setData 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.


  • Qt Champions 2019

    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.


Log in to reply