I have a custom delegate which is added to the first column of a QTableView
. The code is below. I am experiencing a strange rendering issue for the checkboxes on the table view.When all checkboxes visible are checked, the checkboxes render correctly. However, when two or more are unchecked, then the checkbox is not displayed correctly. Please see the example below:
All checked:
Some unchecked:
Unchecking / checking the checkboxes arbitrarily always recaptures this behavior. Curiously, in the case the checkboxes are not rendered correctly, the white check mark flickers, as if it is being partially redrawn but not full extended.
The delegate subclass is as below:
#ifndef BOOLEANITEMDELEGATE_H
#define BOOLEANITEMDELEGATE_H
#include <QItemDelegate>
#include <QSqlTableModel>
class BooleanItemDelegate : public QItemDelegate
{
public:
BooleanItemDelegate(QSqlTableModel* model, QObject* parent);
~BooleanItemDelegate();
public:
void paint(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex& index) const;
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index);
};
#endif // BOOLEANITEMDELEGATE_H
#include "BooleanItemDelegate.h"
#include <qcoreevent.h>
BooleanItemDelegate::BooleanItemDelegate(QSqlTableModel* model, QObject* parent)
: QItemDelegate(parent)
{}
BooleanItemDelegate::~BooleanItemDelegate()
{}
void BooleanItemDelegate::paint(
QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index
) const
{
drawBackground(painter, option, index);
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
drawFocus(painter, option, option.rect);
}
bool BooleanItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
{
if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick )
{
model->setData(index, !model->data(index).toBool());
event->accept();
}
return QItemDelegate::editorEvent(event, model, option, index);
}
Any thoughts on this would be much appreciated!
For me, when I use your implementation of the paint
-method, the data is rendered correctly. The problem might be somewhere else.
I suggest to try the full implementation of the delegate:
CheckboxDelegate.cpp
#include "CheckboxDelegate.h"
#include <QCheckBox>
CheckboxDelegate::CheckboxDelegate(QObject *parent) :
QItemDelegate{parent}
{
}
void CheckboxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
drawBackground(painter, option, index);
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
drawFocus(painter, option, option.rect);
}
QWidget *CheckboxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
{
return new QCheckBox(parent);
}
void CheckboxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
{
editor->move(option.rect.center() - QPoint(8, 8));
editor->resize(16, 16);
}
void CheckboxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
static_cast<QCheckBox *>(editor)->setCheckState(index.data().toBool() ? Qt::Checked : Qt::Unchecked);
}
void CheckboxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
model->setData(index, static_cast<QCheckBox *>(editor)->checkState() == Qt::Checked);
}
You can test the delegate like this:
MainWindow.cpp
#include "MainWindow.h"
#include "CheckboxDelegate.h"
#include <QStandardItemModel>
#include <QTableView>
#include <QBoxLayout>
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
auto *model{new QStandardItemModel(this)};
auto *view{new QTableView(this)};
auto *l{new QVBoxLayout(this)};
for (int n{0}; n < 10; n++)
model->appendRow(new QStandardItem(QString::number(n < 5)));
view->setModel(model);
view->setFrameStyle(QTableView::NoFrame);
view->setItemDelegateForColumn(0, new CheckboxDelegate(this));
view->setEditTriggers(QTableView::CurrentChanged);
l->addWidget(view);
l->setContentsMargins(0, 0, 0, 0);
resize(640, 480);
}
I have created an example project for you. The project is available for download on GitHub.
After manually changing some of the states, the result looks like this: