Ruslan PolupanApril 11, 2019, 6:01 a.m.

QCheckBox в качестве делегата QTableView

Доброго времени суток.
Возникла необходимость использовать делегат для отображения QCheckBox в таблице (выбирать объекты из списка для последующей работы с ними).
Для того чтобы разобратся с делегатами создал небольшой проект.
На выходе получаем следующее:

Структура проекта:

checkboxdelegate.h

#ifndef CHECKBOXDELEGATE_H
#define CHECKBOXDELEGATE_H
#include <QStyledItemDelegate>


class CheckBoxDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
    CheckBoxDelegate(QObject *parent = nullptr);

    // QAbstractItemDelegate interface
public:
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void setEditorData(QWidget *editor, const QModelIndex &index) const;
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

#endif // CHECKBOXDELEGATE_H

checkboxdelegate.cpp

#include "checkboxdelegate.h"
#include <QCheckBox>
#include <QApplication>

CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
    :QStyledItemDelegate (parent)
{

}

QWidget *CheckBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option)
    Q_UNUSED(index)

    //Cоздаем checkbox editor
    QCheckBox *editor = new QCheckBox(parent);
    return editor;
}

void CheckBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    //Установливаем выбрано/не выбрано
    QCheckBox *cb = qobject_cast<QCheckBox *>(editor);
    cb->setChecked(index.data().toBool());
}

void CheckBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    //Записываем данные в модель
    QCheckBox *cb = static_cast<QCheckBox *>(editor);
    int value = (cb->checkState()==Qt::Checked)? 1 : 0;
    model->setData(index, value, Qt::EditRole);
}

void CheckBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    QStyleOptionButton checkboxstyle;
    QRect checkbox_rect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkboxstyle);

    //Центрирование
    checkboxstyle.rect = option.rect;
    checkboxstyle.rect.setLeft(option.rect.x() +
                               option.rect.width()/2 - checkbox_rect.width()/2);

    editor->setGeometry(checkboxstyle.rect);
}


void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //Получаем данные
    bool data = index.model()->data(index, Qt::DisplayRole).toBool();

    //Создаем стиль CheckBox
    QStyleOptionButton checkboxstyle;
    QRect checkbox_rect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkboxstyle);

    //Центрирование
    checkboxstyle.rect = option.rect;
    checkboxstyle.rect.setLeft(option.rect.x() +
                               option.rect.width()/2 - checkbox_rect.width()/2);
    //Выбрано или не выбрано
    if(data)
        checkboxstyle.state = QStyle::State_On|QStyle::State_Enabled;
    else
        checkboxstyle.state = QStyle::State_Off|QStyle::State_Enabled;

    //Готово! Отображаем!
    QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkboxstyle, painter);
}

main.cpp

#include "checkboxdelegate.h"
#include <QApplication>
#include <QStandardItemModel>
#include <QHeaderView>
#include <QTableView>

#define MODEL_ROWS 4            //Количество строк модели
#define MODEL_COLUMN 2          //Количество столбцов модели
#define DELEGATE_COLUMN 0       //Столбец с делегатом

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //Создаем модель и представление
    QStandardItemModel *model = new QStandardItemModel(MODEL_ROWS, MODEL_COLUMN);
    QTableView *tableView = new QTableView();
    CheckBoxDelegate *delegate = new CheckBoxDelegate();

    //Заолняем модель данными
    for (int row =0; row < MODEL_ROWS; ++row) {
        for (int column = 0; column < MODEL_COLUMN; ++column) {
            QModelIndex index = model->index(row, column, QModelIndex());
            if(column == 0)
                model->setData(index, QVariant(0));
            else
                model->setData(index, QVariant((row + 1) * (column + 1)));
        }

    }
    //Устанавливаем модель в представление
    tableView->setModel(model);
    //Устанавливаем делегат в столбец
    tableView->setItemDelegateForColumn(DELEGATE_COLUMN, delegate);
    //Внешний вид предтавления
    tableView->resizeColumnsToContents();
    tableView->verticalHeader()->hide();
    tableView->horizontalHeader()->setStretchLastSection(true);

    tableView->setWindowTitle("Check Box Delegate");
    tableView->show();

    return a.exec();
}

Файл проекта:

CheckBoxDelegate_PG92889.7z CheckBoxDelegate_PG92889.7z

Единственная проблема состоит в том, что для выделения QCheckBox приходится дважны нажимать мышь. Получается что сначала выделяется ячейка. а только потом фокус уже попадает на виджет.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
D
  • #
  • Aug. 11, 2019, 7:50 p.m.

Пример лучше скину после отпуска.

Было бы интересно.

Если это будет достаточно самостоятельный код, то вы бы тогда могли написать небольшую статью на эту тематику в раздел Qt.

D
  • #
  • Aug. 17, 2019, 9:04 a.m.
  • (edited)

github ChekableTView

Правой групповая смена значения при перетаскивании левой как обычно.

m

Единственная проблема состоит в том, что для выделения QCheckBox приходится дважны нажимать мышь. Получается что сначала выделяется ячейка. а только потом фокус уже попадает на виджет.

Ну это как бы не проблема. Это отсутствие решения.

PB

Как изменить цвет фона внутри checkbox (по возможности убрать рамку вокруг)?
Пробовал с цветом так:

QWidget *CheckBoxDelegate::createEditor(QWidget *parent,
                                        const QStyleOptionViewItem &,
                                        const QModelIndex &) const
{
    auto checkBox = new QCheckBox(parent);
    checkBox->setStyleSheet("QCheckBox::indicator {background-color: blue;}");

    return checkBox;
}

Я сейчас просто меняю изображения на CheckBox

    ui->checkBoxIsActive->setStyleSheet(
                      "QCheckBox::indicator:unchecked {image: url(:/Images/check_box_unchek.png);}"
                      "QCheckBox::indicator:checked {image: url(:/Images/check_box.png);}");
PB

Это не то, мне нужно именно делегат отредактировать (без изображения)

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Timeweb

Let me recommend you the excellent hosting on which EVILEG is located.

For many years, Timeweb has been proving his stability.

For projects on Django I recommend VDS hosting

View Hosting
VD

C++ - Test 001. The first program and data types

  • Result:73points,
  • Rating points1
Ds

C++ - Тест 003. Условия и циклы

  • Result:64points,
  • Rating points-1
o

C++ - Test 001. The first program and data types

  • Result:86points,
  • Rating points6
Last comments
RG

QML - Lesson 016. SQLite database and the working with it in QML Qt

Добрый день! можно как то обойтись без метода updateModel()? После вызова этого метода происходит перерисовка страницы(если я правильно понимаю), и все элементы, например, CheckBox перерисовываю…
D:

QML - Lesson 016. SQLite database and the working with it in QML Qt

Добрый день, пытаюсь разобраться и подргнать пример под себя. Есть бд с огромным количеством полей. В приложении на виджетах при использовании QTableView все работает и путем простого sql запрос…

Django - Tutorial 039. Adding private messages and chats on the site - Part 2 (Dialogue and chat counter with unread messages)

Добавляйте поле файла в модель сообщения. И в форме сообщения указывайте, что поле с файлом.
s

Django - Tutorial 023. Like Dislike system using GenericForeignKey

все, я со всем разобрался!) Извините!)
Now discuss on the forum

Наследование QWidget

Это утверждение ничего не значит. Наличие методов и т.д. не делает обязательным наследование в том виде, в котором вы его изначально попытались сделать. Тем более, если у вас будет два видж…

Динамическое заполнение StackLayout в qml

Всем привет. Пытаюсь решить такую задачку, есть TabBar и его кнопки. StackLayout{ currentIndex: tabBar.currentIndex A {id: tabA} B {id: tabB} C {id: tabC} D {id: ta…
M

QML: изменение стиля при наведении и при нажатии на кнопку

enabled = false перестанет быть активной и не будет ни на что реагировать) Хм.. по-моему пробовал такое. Проверю ещё раз после работы. Ура, спасибо большо…
U

Динамическое наполнение StackView QML

Во затупил))) Спасибо за все))) StackView.push("ModuleTip1.qml") ну или в сложной иерархии StackView.push("qrc:/folder/ModuleTip1.qml") и всего делов... Не пойму, почему сра…

QEventLoop тормозит при удалении экземпляра

Думаю, что нет. Лучше вообще без исключений, но не всегда возможно.
About
Services
© EVILEG 2015-2020
Recommend hosting TIMEWEB