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);
}