Adding text and numbers in an QAbstractItemModel was the easy part of the Qt Model/View design.

In this tutorial we are going a bit further by adding a QCheckBox directly on each item of a column.

But instead of using the createEditor() method we’re going to use only the paint() one.

Let’s painting.

First of all

For this example adding a visual QObject is generally made with the createEditor() method.

As the QCheckBox has already a role in the data() method of the QAbtractItemModel class, we’ll use it.

But this QCheckBox is by default on the left with a text area on the right.

So as we want this QCheckBox only in the center we’ll redraw it with the paint() method.

Let’s code a bit.

Code

BadprogData.cpp

#include “BadprogData.h”

// Badprog.com

// ============================================================================

//

// ============================================================================

BadprogData::BadprogData() {

}

// ============================================================================

//

// ============================================================================

BadprogData::~BadprogData() {

}

// ============================================================================

//

// ============================================================================

void BadprogData::setName(QString name) {

_name = name;

}

// ============================================================================

//

// ============================================================================

QString BadprogData::getName() const {

return _name;

}

// ============================================================================

//

// ============================================================================

void BadprogData::setAge(int age) {

_age = age;

}

// ============================================================================

//

// ============================================================================

int BadprogData::getAge() const {

return _age;

}

// ============================================================================

//

// ============================================================================

void BadprogData::setNeedToCompute(bool state) {

_needToCompute = state;

}

// ============================================================================

//

// ============================================================================

bool BadprogData::getNeedToCompute() const {

return _needToCompute;

}

BadprogData.h

#ifndef BADPROG_DATA_H

#define BADPROG_DATA_H

#include

// Badprog.com

class BadprogData

{

public:

BadprogData();

~BadprogData();

// ============================================================================

// methods

// ============================================================================

public:

void setName(QString name);

void setAge(int age);

QString getName() const;

int getAge() const;

void setNeedToCompute(bool state);

bool getNeedToCompute() const;

// ============================================================================

// variables

// ============================================================================

private:

QString _name;

int _age;

bool _needToCompute;

};

#endif // !BADPROG_DATA_H

BadprogDelegateCheckbox.cpp

#include “BadprogDelegateCheckbox.h”

#include

#include

#include

#include

#include

// Badprog.com

// ============================================================================

//

// ============================================================================

BadprogDelegateCheckbox::BadprogDelegateCheckbox(QObject *parent) {

}

// ============================================================================

//

// ============================================================================

BadprogDelegateCheckbox::~BadprogDelegateCheckbox() {

}

// ============================================================================

//

// ============================================================================

void BadprogDelegateCheckbox::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {

//

if (2 == index.column()) {

// inits

Qt::CheckState state = (Qt::CheckState)index.data(Qt::CheckStateRole).toInt();

QStyleOptionButton style;

int x = -1;

int y = -1;

// sets if checkbox is enabled

style.state = QStyle::State_Enabled;

// sets the state

switch (state) {

case Qt::Unchecked:

style.state |= QStyle::State_Off;

break;

case Qt::Checked:

style.state |= QStyle::State_On;

break;

}

// sets the checkbox style

style.rect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &style, nullptr);

x = option.rect.center().x() - style.rect.width() / 2;

y = option.rect.center().y() - style.rect.height() / 2;

style.rect.moveTo(x, y);

// draws the checkbox

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

} else {

//

QStyledItemDelegate::paint(painter, option, index);

}

}

BadprogDelegateCheckbox.h

#ifndef BADPROG_DELEGATE_CHECKBOX_H

#define BADPROG_DELEGATE_CHECKBOX_H

#include

// Badprog.com

class BadprogDelegateCheckbox : public QStyledItemDelegate {

// ============================================================================

// ctor

// ============================================================================

public:

BadprogDelegateCheckbox(QObject *parent = 0);

~BadprogDelegateCheckbox();

// ============================================================================

// methods

// ============================================================================

public:

// override

//

void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;

};

#endif // !BADPROG_DELEGATE_CHECKBOX_H

BadprogItemModel.cpp

#include “BadprogItemModel.h”

#include

#include

// Badprog.com

// ============================================================================

//

// ============================================================================

BadprogItemModel::BadprogItemModel() {

}

// ============================================================================

//

// ============================================================================

BadprogItemModel::BadprogItemModel(int numberOfRows, int numberOfColumns) :

_numberOfRows(numberOfRows), _numberOfColumns(numberOfColumns) {

}

// ============================================================================

//

// ============================================================================

BadprogItemModel::~BadprogItemModel() {

}

// ============================================================================

//

// ============================================================================

QVariant BadprogItemModel::data(const QModelIndex &index, int role) const {

//

QVariant result = QVariant();

int row = index.row();

int column = index.column();

//

if (!index.isValid() || row >= rowCount() || column >= columnCount()) {

return result;

}

//

switch (role) {

//

case Qt::DisplayRole:

// checking row and column to get data

switch (column) {

case 0:

result = _data.at(row).getName();

break;

case 1:

result = _data.at(row).getAge();

break;

case 2:

result = _data.at(row).getNeedToCompute();

break;

default:

break;

} // end switch column

break;

//

case Qt::FontRole:

//

if (2 == row) {

QFont font;

font.setBold(true);

result = font;

}

break;

//

case Qt::ForegroundRole:

//

if (1 == column) {

result = QColor(Qt::red);

}

break;

//

case Qt::BackgroundRole:

//

if (1 == column) {

result = QColor(255, 255, 40);

}

break;

//

case Qt::TextAlignmentRole:

result = Qt::AlignCenter;

break;

//

case Qt::CheckStateRole:

//

if (column == 2) {

result = _data.at(row).getNeedToCompute();

//

if (true == result) {

result = Qt::CheckState::Checked;

} else {

result = Qt::CheckState::Unchecked;

}

}

break;

default:

break;

}

//

return result;

}

// ============================================================================

//

// ============================================================================

int BadprogItemModel::rowCount(const QModelIndex &parent) const {

(void)(parent);

return _numberOfRows;

}

// ============================================================================

//

// ============================================================================

int BadprogItemModel::columnCount(const QModelIndex &parent) const {

(void)(parent);

return _numberOfColumns;

}

// ============================================================================

//

// ============================================================================

QVariant BadprogItemModel::headerData(int section, Qt::Orientation orientation, int role) const {

//

QVariant result = QVariant();

//

if (Qt::DisplayRole == role && Qt::Horizontal == orientation) { // H

//

switch (section) {

//

case 0:

result = “Hello”;

break;

//

case 1:

result = “World”;

break;

//

case 2:

result = “:D”;

break;

default:

break;

}

} else if (Qt::DisplayRole == role && Qt::Vertical == orientation) { // V

//

switch (section) {

//

case 0:

result = “Welcome”;

break;

//

case 1:

result = “Aboard”;

break;

//

case 2:

result = “Guys”;

break;

default:

break;

}

} else {

// other stuff

}

//

return result;

}

// ============================================================================

//

// ============================================================================

bool BadprogItemModel::setData(const QModelIndex &index, const QVariant &value, int role) {

//

bool result = false;

int row = index.row();

int column = index.column();

if (index.isValid() && role == Qt::EditRole) {

//

switch (column) {

case 0:

_data.at(row).setName(value.toString());

break;

case 1:

_data.at(row).setAge(value.toInt());

break;

case 2:

_data.at(row).setNeedToCompute(value.toBool());

break;

default:

break;

} // end switch column

emit dataChanged(index, index);

result = true;

}

//

return result;

}

// ============================================================================

//

// ============================================================================

Qt::ItemFlags BadprogItemModel::flags(const QModelIndex &index) const {

//

Qt::ItemFlags result = QAbstractItemModel::flags(index);

//

if (index.isValid() && (2 != index.column())) {

result |= Qt::ItemIsEditable;

}

//

return result;

}

// ============================================================================

//

// ============================================================================

QModelIndex BadprogItemModel::index(int row, int column, const QModelIndex &parent) const {

return createIndex(row, column, nullptr);

}

// ============================================================================

//

// ============================================================================

QModelIndex BadprogItemModel::parent(const QModelIndex &child) const {

return QModelIndex();

}

// ============================================================================

//

// ============================================================================

void BadprogItemModel::addNewElementToData(BadprogData data) {

_data.push_back(data);

}

// ============================================================================

//

// ============================================================================

std::vector BadprogItemModel::getElementsFromData() const {

return _data;

}

BadprogItemModel.h

#ifndef BADPROG_ITEM_MODEL_H

#define BADPROG_ITEM_MODEL_H

#include “BadprogData.h”

#include

// Badprog.com

class BadprogItemModel : public QAbstractItemModel

{

// ============================================================================

// ctor

// ============================================================================

public:

BadprogItemModel();

BadprogItemModel(int numberOfRows, int numberOfColumns);

~BadprogItemModel();

// ============================================================================

// methods

// ============================================================================

public:

// override from virtual pure

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

int rowCount(const QModelIndex &parent = QModelIndex()) const override;

int columnCount(const QModelIndex &parent = QModelIndex()) const override;

QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;

QModelIndex parent(const QModelIndex &child) const;

// override from virtual

QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;

bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

Qt::ItemFlags flags(const QModelIndex &index) const override;

// classic

void addNewElementToData(BadprogData data);

std::vector getElementsFromData() const;

// ============================================================================

// variables

// ============================================================================

private:

std::vector _data;

int _numberOfRows;

int _numberOfColumns;

};

#endif // !BADPROG_ITEM_MODEL_H

BadprogMainWindow.cpp

#include “BadprogMainWindow.h”

#include “BadprogItemModel.h”

#include “BadprogDelegateCheckbox.h”

#include

#include

#include

// Badprog.com

// ============================================================================

//

// ============================================================================

BadprogMainWindow::BadprogMainWindow(QWidget *parent) : QMainWindow(parent) {

// inits

ui.setupUi(this);

_model = nullptr;

unsigned int numberOfRows = 0;

unsigned int numberOfColumns = 3;

QTextStream stream;

QFile file = nullptr;

bool result = false;

// file

_fileName = “people.txt”;

file.setFileName(_fileName);

// deals with the file

result = managerFile(file, QIODevice::ReadOnly);

stream.setDevice(&file);

// number of lines

managerNumberOfLines(stream, numberOfRows);

_model = new BadprogItemModel(numberOfRows, numberOfColumns);

// reading the file

managerReadFile(stream);

// setting the model

ui.tableView->setModel(_model);

ui.listView->setModel(_model);

// settings the delegate

_delegate = new BadprogDelegateCheckbox(this);

ui.tableView->setItemDelegate(_delegate);

//

QObject::connect(

ui.tableView, &QTableView::clicked,

this, &BadprogMainWindow::slotGetClickItem

);

// if file exists we allow saving mode

if (result) {

QObject::connect(

ui.pushButton, &QPushButton::clicked,

this, &BadprogMainWindow::slotSaveData);

}

}

// ============================================================================

//

// ============================================================================

void BadprogMainWindow::managerNumberOfLines(QTextStream &stream, unsigned int &numberOfRows) {

// gets number of lines

while (!stream.atEnd()) {

stream.readLine();

++numberOfRows;

}

stream.seek(0); // sets the cursor to begin

}

// ============================================================================

//

// ============================================================================

void BadprogMainWindow::managerReadFile(QTextStream &stream) {

//

while (!stream.atEnd()) {

QString line = stream.readLine();

QStringList fields = line.split("::");

BadprogData data;

data.setName(fields.at(0));

data.setAge(fields.at(1).toInt());

bool state = false;

if (fields.at(2) == “true”) {

state = true;

}

data.setNeedToCompute(state);

_model->addNewElementToData(data);

}

}

// ============================================================================

//

// ============================================================================

bool BadprogMainWindow::managerFile(QFile &file, QIODevice::OpenModeFlag flag) {

//

bool result = true;

//

if (!file.open(flag)) {

QMessageBox::information( // parent, title, message

this,

“Problem with the file”,

“File: "” + file.fileName() + “".\n” + file.errorString());

result = false;

}

//

return result;

}

// ============================================================================

//

// ============================================================================

void BadprogMainWindow::slotSaveData() {

// inits

QFile file;

QTextStream out;

QString delimiter = “::”;

//

file.setFileName(_fileName);

managerFile(file, QIODevice::WriteOnly);

// writing to the file

out.setDevice(&file);

for (auto &element : _model->getElementsFromData()) {

QString state = “false”;

if (element.getNeedToCompute()) {

state = “true”;

}

out « element.getName() « delimiter « element.getAge() « delimiter « state;

out « “\n”;

}

}

// ============================================================================

//

// ============================================================================

void BadprogMainWindow::slotGetClickItem(const QModelIndex &index) {

//

if (index.isValid() && (2 == index.column())) {

//

bool state = index.data().toBool();

//

_model->setData(index, !state, Qt::EditRole);

}

}

BadprogMainWindow.h

#ifndef BADPROG_MAIN_WINDOW_H

#define BADPROG_MAIN_WINDOW_H

#include “ui_BadprogMainWindow.h”

#include “BadprogItemModel.h”

#include

// Badprog.com

class QFile;

class BadprogDelegateCheckbox;

class BadprogMainWindow : public QMainWindow

{

Q_OBJECT

// ============================================================================

// ctor

// ============================================================================

public:

BadprogMainWindow(QWidget *parent = Q_NULLPTR);

// ============================================================================

// methods

// ============================================================================

public:

bool managerFile(QFile &file, QIODevice::OpenModeFlag flag);

void managerNumberOfLines(QTextStream &stream, unsigned int &numberOfRows);

void managerReadFile(QTextStream &stream);

// ============================================================================

// slots

// ============================================================================

public slots:

void slotSaveData();

void slotGetClickItem(const QModelIndex &index);

// ============================================================================

//

// ============================================================================

private:

Ui::BadprogMainWindowClass ui;

QPointer _model;

QString _fileName;

QPointer _delegate;

};

#endif // !BADPROG_MAIN_WINDOW_H

BadprogMainWindow.ui

BadprogMainWindowClass

0

0

1345

400

BadprogMainWindow

Save data

0

0

1345

21

TopToolBarArea

false

main.cpp

#include “BadprogMainWindow.h”

#include <QtWidgets/QApplication>

// Badprog.com

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

BadprogMainWindow w;

w.show();

return a.exec();

}

people.txt

I'm here::9854::true
John::12::false
Jack::1525::true

Result

Each time you click on a QCheckBox the state changes.

Conclusion

This paint() method is great.

Indeed, with it you can do whatever you want by modifying the GUI.

If you got it, good job, once a gain you did it.