Qt Tree View with Checboxes

0

I modified the example of the Qt website: EditableTreeModel Example so that in the tree view I get CheckBoxes next to each Item.

But ... How can I make them dependent on each other? That is, if the parent's ChechBox is selected automatically, check all of their children. And if one of those children later becomes Uncheck, the father becomes partially checkered.

Here the functions that I have modified to make the CheckBoxes come out.

In TreeModel function data :

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()){
        return QVariant();
    }
    TreeItem *item1 = static_cast<TreeItem*>(index.internalPointer());

    if ( role == Qt::CheckStateRole && index.column() == 0 )
    {
        return static_cast< int >( item1->isChecked() ? Qt::Checked : Qt::Unchecked );
    }
    if (role != Qt::DisplayRole && role != Qt::EditRole)
        return QVariant();

    TreeItem *item = getItem(index);

    return item->data(index.column());
}

In TreeModel function flags :

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;

    return Qt::ItemIsEditable | QAbstractItemModel::flags(index)|Qt::ItemIsUserCheckable;
}

In TreeModel function setData :

bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    TreeItem *item = getItem(index);
    if(role == Qt::CheckStateRole)
    {
        qDebug()<<"Ischecked"<<item->isChecked();

        if(item->isChecked())
            item->setChecked(false);
        else
            item->setChecked(true);
        emit dataChanged(index, index);
        return true;
    }

    if (role != Qt::EditRole)
        return false;
    bool result = item->setData(index.column(), value);


    if (result)
        emit dataChanged(index, index);

    return result;
}

In TreeItem I added the function setChecked again:

void TreeItem::setChecked(bool set)
{
    checked=set;
}

In TreeItem I added the function isChecked again:

bool TreeItem::isChecked()
{
    return checked;
}

Being checked a variable type bool within my class TreeItem .

    
asked by MAP 21.11.2018 в 15:03
source

1 answer

3

You have to spread the event by hand. For this you could make recursive calls to setData , but the result can be excessively slow because, among other things, it involves launching the dataChanged event once for each modified row.

Another option would be to create a function that propagates the change and that, at the same time, groups the signal emission:

void TreeModel::PropagateCheckedValue(QModelIndex const& parentIndex, TreeItem const& parent, bool value)
{
  for( int i=0; i<parent.childCount(); i++ )
  {
    TreeItem* child = parent.child(i);

    QModelIndex modelIndex = index(0,0,parentIndex);
    child->setChecked(value);
    PropagateCheckedValue(modelIndex,*child,value);
  }

  if( parent.childCount() > 0 )
  {
    QModelIndex begin = index(0,0,parentIndex);
    QModelIndex end = index(parent.childCount()-1,0,parentIndex);
    emit dataChanged(begin,end);
  }
}

bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    TreeItem *item = getItem(index);
    if(role == Qt::CheckStateRole)
    {
        bool checked = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked);
        item->setChecked(checked);
        PropagateCheckedValue(index,*item,checked);

        emit dataChanged(index, index);
        return true;
    }

By the way, note that now the value of checked is retrieved from value instead of just inverting the state of checked . This is done because setData is a public function that can be invoked from anywhere.

It could, for example, give the case of a call to setData to activate a check that is already active, which in your case would cause the check to be disabled.

    
answered by 21.11.2018 / 15:42
source