[Qt-interest] Qt::CheckStateRole

Willy P willy.lists at gmail.com
Fri Sep 18 07:58:01 CEST 2009


Thanks all!  I ended up doing it myself and it wasn't that bad,
similar to your approach Sean.  Appreciate the help.

-Willy


On Thu, Sep 17, 2009 at 1:22 AM, Sean Harmer
<sean.harmer at maps-technology.com> wrote:
> Hi,
>
> On Thursday 17 Sep 2009 02:06:56 Willy P wrote:
>> I've implemented my own model by inheriting from QAbstractItemModel
>> and my own view by inheriting from QTreeView.  I've got all the
>> parents and children showing up and I've got checkboxes showing up
>> next to them in their proper state.  Checking and unchecking items is
>> properly setting the values in the model, but they're not cascading up
>> the chain to the parents.  In other words, in the view, a parent's
>> check state is not Qt::PartiallyChecked when only some of it's
>> children are checked.  How do I get the automatic updating of parent's
>> and children's checkboxes?  Or do I have to do that myself?
>>
>> Thanks in advance...
> I think you have to do this yourself. Here is some snippets of how I did it a
> couple of years ago. (Bear in mind I was still learning the model/view API
> then so there may be a better way of doing this).
>
> In your model's setData function have a section like this:
>
> bool MyModel::setData( const QModelIndex& index, const QVariant& value, int
> role )
> {
>    if ( role == Qt::CheckStateRole )
>    {
>        Node* item = static_cast<Node*>( index.internalPointer() );
>        Qt::CheckState state = Qt::Checked;
>        if ( item->checkState() == Qt::Checked )
>            state = Qt::Unchecked;
>        item->setCheckState( state );
>        if ( item->itemType() == Node::File )
>        {
>            QModelIndex highestChanged = propagateCheckStateToRoot( index,
> state );
>            emit dataChanged( highestChanged, index );
>            emit layoutChanged();
>        }
>        else
>        {
>            // For (un)checking a group we must recurse down and apply the
>            // change to all children too
>            QModelIndex lowestChanged;
>            QModelIndex highestChanged =
>                propagateCheckStateToLeaves( index, lowestChanged,
>                                                                    state,true);
>            emit dataChanged( highestChanged, lowestChanged );
>            emit layoutChanged();
>        }
>        return true;
>    }
>
>    return false;
> }
>
> This assumes that we have two types of node in our model leaf nodes and
> grouping nodes and takes care of calling either propagateCheckStateToLeaves or
> propagateCheckStateToRoot as needed. The implementation of these functions
> are:
>
> QModelIndex MyModel::propagateCheckStateToRoot( const QModelIndex& index,
> Qt::CheckState state )
> {
>    QModelIndex parent = index.parent();
>    if ( parent.isValid() )
>    {
>        Node* parentItem = static_cast<Node*>( parent.internalPointer() );
>        Qt::CheckState parentState = parentItem->checkState();
>
>        if ( !childrenAllSameSelectionState( parent ) )
>            state = Qt::PartiallyChecked;
>
>        if ( parentState != state )
>        {
>            setCheckState( parent, state );
>            return propagateCheckStateToRoot( parent, state );
>        }
>        return index;
>    }
>
>    return parent;
> }
>
>
> QModelIndex MyModel::propagateCheckStateToLeaves( const QModelIndex& index,
>    QModelIndex& lowest, Qt::CheckState state, bool initiator )
> {
>    if ( hasChildren( index ) )
>    {
>        // Recurse this call into the children
>        for ( int i = 0; i < rowCount( index ); i++ )
>        {
>            QModelIndex child = MyModel::index( i, 0, index );
>            propagateCheckStateToLeaves( child, lowest, state );
>        }
>    }
>    else
>    {
>        // The item referenced by index has no children.
>        // Set the state and record the index
>        setCheckState( index, state );
>        lowest = index;
>    }
>
>    if ( initiator )
>        return propagateCheckStateToRoot( index, state );
>
>    return index;
> }
>
>
> And finally these function use a couple of small helpers:
>
> bool MyModel::childrenAllSameSelectionState( const QModelIndex& parent ) const
> {
>    if ( !parent.isValid() )
>        return false;
>
>    Node* parentItem = static_cast<Node*>( parent.internalPointer() );
>    if ( parentItem->itemType() != Node::Group )
>        return false;
>
>    GroupItem* group = static_cast<GroupItem*>( parentItem );
>    if ( group->childCount() == 0 || group->childCount() == 1 )
>        return true;
>
>    Qt::CheckState state = group->child( 0 )->checkState();
>    for ( int i = 1; i < group->childCount(); i++ )
>    {
>        if ( group->child( i )->checkState() != state )
>            return false;
>    }
>
>    return true;
> }
>
> void MyModel::setCheckState( const QModelIndex& index, Qt::CheckState state )
> {
>    if ( !index.isValid() )
>        return;
>
>    Node* item = static_cast<Node*>( index.internalPointer() );
>    item->setCheckState( state );
> }
>
> Anyway, you should be able to get the idea from this and port it to your
> specific case.
>
> HTH,
>
> Sean
> _______________________________________________
> Qt-interest mailing list
> Qt-interest at trolltech.com
> http://lists.trolltech.com/mailman/listinfo/qt-interest
>




More information about the Qt-interest-old mailing list