简体   繁体   中英

QTreeView Checkboxes

I know this has been asked a bunch of times, but I cant seem to find anything relevant.

Using the simpletreemodel tutorial that comes packaged with Qt, how would I add checkboxes?

Firstly, you'll need to modify TreeItem to keep track of the checked state:

private:
    ...
    bool checked;

and a setter and getter:

bool isChecked() const { return checked; }
void setChecked( bool set ) { checked = set; }

Now the model will need to be modified so that the view knows about the check state:

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

    if ( role == Qt::CheckStateRole && index.column() == 0 )
        return static_cast< int >( item->isChecked() ? Qt::Checked : Qt::Unchecked );

    if (role != Qt::DisplayRole)
        return QVariant();

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

and modify the model's flags method to let views know that the model contains checkable items:

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

    Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;

    if ( index.column() == 0 )
        flags |= Qt::ItemIsUserCheckable;

    return flags;
}

I think this should do it. If you want to be able to update the TreeItem check state when the user ticks and unpicks the items, then you'll need to provide the QAbstractItemModel::setData method in your TreeModel.

I converted the above to PyQt for my own purposes and figured I'd share.

def data(self, index, role):
    if not index.isValid():
        return None

    item = index.internalPointer();

    if role == Qt.CheckStateRole and index.column() == self.check_col:
        return int( Qt.Checked if item.isChecked() else Qt.Unchecked )

    return super(TreeModel, self).data(index, role)


def flags(self, index):
    if not index.isValid():
        return None

    if index.column() == self.check_col:
        flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsUserCheckable
    else:
        flags = super(TreeModel, self).flags(index)

    return flags


def setData(self, index, value, role=Qt.EditRole):
    if index.column() == self.check_col:
        if role == Qt.EditRole:
            return False
        if role == Qt.CheckStateRole:
            item = self.getItem(index)
            item.setChecked(value)
            self.dataChanged.emit(index, index)
            return True

    return super(TreeModel, self).setData(index, value, role)

Here is another PyQt complete woking example using QStandardItemModel :

model = QStandardItemModel()
parent_item = model.invisibleRootItem()  # type: QStandardItem
for row in [
    (Qt.Unchecked, 'unchecked'),
    (Qt.PartiallyChecked, 'partially'),
    (Qt.Checked, 'checked')
]:
    checked, text = row
    check_item = QStandardItem('')
    check_item.setCheckable(True)
    check_item.setCheckState(checked)
    parent_item.appendRow([check_item, QStandardItem(text)])
treeview.setModel(model)

Btw, this should also work for any C++ applications.

I just want to complete @JediLlama's answer by adding the setData method, translated from @taynaron's Python version:

bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role) {
    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

    if (index.column() == 0) {
        if (role == Qt::EditRole) {
            return false;
        }
        if (role == Qt::CheckStateRole) {
            item->setCheck(value.toBool());
            emit dataChanged(index, index);
            return true;
        }
    }

    return QAbstractItemModel::setData(index, value, role);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM