1

I use a QTreeView with a TreeModel (that inherits QAbstractItemModel). The TreeModel::flags() function returns Qt::ItemIsUserCheckable and therefore a checkbox is displayed besides every item in the view. What I need to do is display the checkbox as disabled when the parent item is not checked but the user must be able to interact with it normally (the checkbox must be enabled).

I tried to implement a custom QStyledItemDelegate and draw the checkbox myself. However I don't know how to use custom images when drawing the checkbox at the draw() function of the delegate. I don't even know if this is the right way to do it.

I also thought of using stylesheets somehow, but the display of the checkbox depends on the model data (if the parent is checked or not).

Any Ideas?

This is my ItemDelegate::paint() function.

void ItemDelegate::paint(QPainter *painter,
                         const QStyleOptionViewItem &option,
                         const QModelIndex &index) const
{
    int value = index.model()->data(index, Qt::DisplayRole).toInt();

    QStyleOptionButton check_box_style_option;

    check_box_style_option.state |= QStyle::State_Enabled;

    if (value == 1)
        check_box_style_option.state |= QStyle::State_On;
    else
        check_box_style_option.state |= QStyle::State_Off;

    check_box_style_option.rect = option.rect;


    QApplication::style()->drawControl(QStyle::CE_CheckBox,
                                       &check_box_style_option, painter);
}

[Edit] TreeModel code. The tree model is based on the "simpletreemodel" example. I changed flags() to also return Qt::ItemIsUserCheckable and data(), setData() to enable the checkboxes to be checked and unchecked.

#include <QtGui>
#include <QDebug>
#include "treeitem.h"
#include "treemodel.h"

TreeModel::TreeModel(Container *data, QObject *parent)
    : QAbstractItemModel(parent)
{
    root_item_ = new TreeItem("");
    SetupModelData(data, root_item_);
}

TreeModel::~TreeModel()
{
    delete root_item_;
}

int TreeModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
    else
        return root_item_->columnCount();
}

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->checked()) ? Qt::Checked : Qt::Unchecked;

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

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

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

    if(role == Qt::CheckStateRole)
        item->set_checked(!item->checked());

    if(role == Qt::EditRole)
    {
        qDebug() << "value:" << value.toString();
        item->set_data(value.toString());
    }

    emit dataChanged(index, index);

    return true;
}

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

    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
}

QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
        return root_item_->data(section);

    return QVariant();
}

QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
            const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    TreeItem *parentItem;

    if (!parent.isValid())
        parentItem = root_item_;
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    TreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
    TreeItem *parentItem = childItem->parent();

    if (parentItem == root_item_)
        return QModelIndex();

    return createIndex(parentItem->row(), 0, parentItem);
}

int TreeModel::rowCount(const QModelIndex &parent) const
{
    TreeItem *parentItem;
    if (parent.column() > 0)
        return 0;

    if (!parent.isValid())
        parentItem = root_item_;
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    return parentItem->childCount();
}

void TreeModel::SetupModelData(Container *data, TreeItem *parent)
{
    TreeItem *new_item = new TreeItem(data->id(), parent);
    data->set_tree_item(new_item);
    parent->appendChild(new_item);

    foreach(Container *child, data->children())
        SetupModelData(child, new_item);
}
apon
  • 85
  • 1
  • 10
  • What about enabling it temporarily when the user hovers over it with the mouse? – sashoalm Nov 22 '12 at 10:48
  • 1
    How can I achieve this behavior? Will it be implemented in the delegate? – apon Nov 22 '12 at 11:01
  • See http://stackoverflow.com/q/4333116/492336 – sashoalm Nov 22 '12 at 11:02
  • 1
    ok, but how can I get access to the checkbox? Can I access it through the TreeModel? – apon Nov 22 '12 at 11:17
  • Please put the code where you´re creating your tree model and your check box. – Synxis Nov 22 '12 at 11:20
  • @apon I see now that the checkbox is in the tree model. In this case try using [QTreeView::indexAt](http://doc.qt.digia.com/qt/qtreeview.html#indexAt) – sashoalm Nov 22 '12 at 12:37
  • I imagine you propose to implement the mouseMoveEvent of the QTreeView and get the event->pos(). Then use the mouse position to get the model index by QTreeView::indexAt() (Is that right?). But even if I have the model index, how will I access the checkbox object so that I can enable or disable it? – apon Nov 22 '12 at 13:15

0 Answers0