Подсказки на компьютерную тематику

Можно подсмотреть, если забыли…

Как в Qt Creator вывести Radiobutton и Checkbox в модели TableView

Пример вывода элементов выбора строк в модели QSqlTableModel для Tableview через делегат

Qt использование checkbox и radiobutton в tableview

    Файлы проекта, работающего с базой данных SQLite должны выглядеть примерно так:


  • Компоновочный файл Qt_tablewidget_checkbox_with_DB.pro:
  • QT += core gui sql
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    CONFIG += c++11

    # You can make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

    SOURCES += \
    delegate.cpp \
    main.cpp \
    mainwindow.cpp

    HEADERS += \
    delegate.h \
    mainwindow.h

    FORMS += \
    mainwindow.ui

    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target


  • Заголовочный файл создаваемого требуемого делегата delegate.h:
    #ifndef CHECKBOXDELEGATE_H
    #define CHECKBOXDELEGATE_H
    #include "QStyledItemDelegate"
    class CheckBoxDelegate : public QStyledItemDelegate
    {
    Q_OBJECT
    public:
    CheckBoxDelegate(QObject *parent = nullptr);

    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


  • Файл для делегата delegate.cpp:
    #include "delegate.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
    {
    //Записать данные в модель, если нажата пишет 1 иначе 0
    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);
    }
    //createEditor() returns the widget used to change data from the model and can be reimplemented to customize editing behavior.
    //setEditorData() provides the widget with data to manipulate.
    //updateEditorGeometry() ensures that the editor is displayed correctly with respect to the item view.
    //setModelData() returns updated data to the model.


  • Заголовочный стандартный файл mainwindow.h с объявленными функциями:
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include "QMainWindow"
    #include "QtSql"
    #include "QSqlDatabase"

    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    private:
    Ui::MainWindow *ui;

    private slots:
    void tableviewfunction();//основная функция, выводящая таблицу в tableView

    void forworktableview();//получение индекса ячейки в tablevidget через checkbox или radiobutton

    };
    #endif // MAINWINDOW_H


  • Главный файл main.cpp можно оставить как есть:
    #include "mainwindow.h"
    #include "delegate.h"
    #include "QApplication"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
    }


  • Основной файл mainwindow.cpp:
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "delegate.h"

    #include "QTableView"//добавлено для вывода БД в таблице
    #include "QStandardItemModel"//добавлено для вывода БД в таблице
    #include "QStandardItem"//добавлено для вывода БД в таблице

    #include "QCheckBox"//добавлено для вывода QCheckBox в таблице
    #include "QRadioButton"//добавлено для вывода QRadioButton в таблице
    #include "QStyledItemDelegate"

    #include "QDebug"

    //для СПОСОБА 1
    //int columndelegatenumber=5;//номер уже созданной колонки для делегата, выбираем созданную таблицу в самой бд со значениями int 0

    //для СПОСОБА 2
    int columndelegatenumber=0;//номер колонки для делегата, можно выбрать любую существующую колонку с другими значениями типа int, например
    //с порядковыми номерами ID
    //и программно заменить их в таблице на 0, при этом не сохраняя их в базе данных!

    /*для исправления ошибки QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed
    подключать драйвер для БД (обычно доступно несколько драйверов, их список содержится в стандартном методе QSqlDatabase::drivers();)
    следует в глобальной переменной static (видно везде в одном файле) или extern (видно везде во всех файлах) */
    static QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");// db - это статическая глобальная переменная, которую можно использовать только в этом файле

    MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    tableviewfunction();//основная функция, выводящая таблицу в tableView
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(forworktableview()));//получение значений всех ячеек в tableview через выбранные checkbox и radiobutton
    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    void MainWindow::tableviewfunction(){//основная функция, выводящая таблицу в tableView
    //основная функция, выводящая таблицу

    //подключить БД по ее адресу на компьютере
    db.setDatabaseName("/home/mishanyya/databaseexample/examplebdfordbwork");
    //открывает базу данных, указанную в db.setDatabaseName("/home/mishanyya/databaseexample/examplebdfordbwork");
    db.open();

    //СЛЕДУЕТ СОЗДАТЬ в таблице отдельное поле/колонку со значениями типа bool или integer
    QTableView *tableView = ui->tableView;//выбрать объект tableView
    QSqlTableModel *model = new QSqlTableModel;
    model->setTable("basetable");//в модель помещается таблица из БД
    CheckBoxDelegate *delegate = new CheckBoxDelegate();//создать объекта делегата

    //СПОСОБ 1
    //model->select();

    //СПОСОБ 2, Более предпочтительный!
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);//настраивается редактирование таблицы для внесения значений в столбец
    model->select();
    int countrows=model->rowCount();//кол-во строк
    for (int i=0;isetData(model->index(i, columndelegatenumber),QVariant(0));
    }

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

    void MainWindow::forworktableview(){//получение значения ячейки в tableview через checkbox
    int countrows=ui->tableView->model()->rowCount();

    //Получаем данные
    for (int row =0; row < countrows; ++row) { QModelIndex index = ui->tableView->model()->index(row, columndelegatenumber, QModelIndex());//установка индекса - columndelegatenumber колонка в каждой строке

    QVariant value=ui->tableView->model()->data(index).toBool();//поместить в переменную значение ячейки
    //так как там установлен делегат для checkbox должны быть значения
    //1 - если нажат checkbox и 0 - если не нажат checkbox
    //qDebug() << "информация = " << value; if(value==1){ QModelIndex index1 = ui->tableView->model()->index(row, 0, QModelIndex());//установка индекса - 0 колонка в каждой строке
    QVariant value1=ui->tableView->model()->data(index1);//поместить в переменную значение ячейки
    qDebug() << "выбрано значение = " << value1; //ВАЖНО: //так как данные 0 и 1 сохраняются в БД, в дальнейшем их надо проверять в таблице БД, хотя при удалении, может и не надо } } }


  • В файле дизайнере mainwindow.ui требуется добавить элементы графики pushButton и tableView.

Важные особенности при работе tableView и моделей, работающих с базами данных QSqlQueryModel и QSqlQueryModel

    Внимание:

  • при добавлении колонки в модель с помощью метода insertColumn в этот столбец можно будет вставить какой-либо делегат класса QStyledItemDelegate, но нельзя будет его изменять, так как например для работы с checkbox в ячейках должны храниться данные 0 или 1. Если этих значений в колонке не будет, то и работать делегат не сможет
  • поэтому для добавления делегата нужно создать колонку в самой таблице базы данных и тогда делегат, например checkbox сможет работать полноценно, или же без создания дополнительного столбца в БД выбрать существующее поле с ненужными данными в этот момент, например с порядковыми номерами ID и программно заменить их на нулевые значения, но без сохранения этих чисел в таблице БД!!!
  • если надо вставить данные в таблицу программным методом, режим редактирования должен быть следующим - model->setEditStrategy(QSqlTableModel::OnManualSubmit);

Как в Qt Creator вывести Radiobutton и Checkbox в модели TableView

Пример вывода элементов выбора строк в модели QSqlTableModel для Tableview через делегат

Qt использование checkbox и radiobutton в tableview

    Файлы проекта, работающего с базой данных SQLite должны выглядеть примерно так:


  • Компоновочный файл Qt_tablewidget_checkbox_with_DB.pro:
  • QT += core gui sql
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    CONFIG += c++11

    # You can make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

    SOURCES += \
    delegate.cpp \
    main.cpp \
    mainwindow.cpp

    HEADERS += \
    delegate.h \
    mainwindow.h

    FORMS += \
    mainwindow.ui

    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target


  • Заголовочный файл создаваемого требуемого делегата delegate.h:
    #ifndef CHECKBOXDELEGATE_H
    #define CHECKBOXDELEGATE_H
    #include "QStyledItemDelegate"
    class CheckBoxDelegate : public QStyledItemDelegate
    {
    Q_OBJECT
    public:
    CheckBoxDelegate(QObject *parent = nullptr);

    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


  • Файл для делегата delegate.cpp:
    #include "delegate.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
    {
    //Записать данные в модель, если нажата пишет 1 иначе 0
    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);
    }
    //createEditor() returns the widget used to change data from the model and can be reimplemented to customize editing behavior.
    //setEditorData() provides the widget with data to manipulate.
    //updateEditorGeometry() ensures that the editor is displayed correctly with respect to the item view.
    //setModelData() returns updated data to the model.


  • Заголовочный стандартный файл mainwindow.h с объявленными функциями:
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include "QMainWindow"
    #include "QtSql"
    #include "QSqlDatabase"

    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    private:
    Ui::MainWindow *ui;

    private slots:
    void tableviewfunction();//основная функция, выводящая таблицу в tableView

    void forworktableview();//получение индекса ячейки в tablevidget через checkbox или radiobutton

    };
    #endif // MAINWINDOW_H


  • Главный файл main.cpp можно оставить как есть:
    #include "mainwindow.h"
    #include "delegate.h"
    #include "QApplication"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
    }


  • Основной файл mainwindow.cpp:
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "delegate.h"

    #include "QTableView"//добавлено для вывода БД в таблице
    #include "QStandardItemModel"//добавлено для вывода БД в таблице
    #include "QStandardItem"//добавлено для вывода БД в таблице

    #include "QCheckBox"//добавлено для вывода QCheckBox в таблице
    #include "QRadioButton"//добавлено для вывода QRadioButton в таблице
    #include "QStyledItemDelegate"

    #include "QDebug"

    //для СПОСОБА 1
    //int columndelegatenumber=5;//номер уже созданной колонки для делегата, выбираем созданную таблицу в самой бд со значениями int 0

    //для СПОСОБА 2
    int columndelegatenumber=0;//номер колонки для делегата, можно выбрать любую существующую колонку с другими значениями типа int, например
    //с порядковыми номерами ID
    //и программно заменить их в таблице на 0, при этом не сохраняя их в базе данных!

    /*для исправления ошибки QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed
    подключать драйвер для БД (обычно доступно несколько драйверов, их список содержится в стандартном методе QSqlDatabase::drivers();)
    следует в глобальной переменной static (видно везде в одном файле) или extern (видно везде во всех файлах) */
    static QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");// db - это статическая глобальная переменная, которую можно использовать только в этом файле

    MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    tableviewfunction();//основная функция, выводящая таблицу в tableView
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(forworktableview()));//получение значений всех ячеек в tableview через выбранные checkbox и radiobutton
    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    void MainWindow::tableviewfunction(){//основная функция, выводящая таблицу в tableView
    //основная функция, выводящая таблицу

    //подключить БД по ее адресу на компьютере
    db.setDatabaseName("/home/mishanyya/databaseexample/examplebdfordbwork");
    //открывает базу данных, указанную в db.setDatabaseName("/home/mishanyya/databaseexample/examplebdfordbwork");
    db.open();

    //СЛЕДУЕТ СОЗДАТЬ в таблице отдельное поле/колонку со значениями типа bool или integer
    QTableView *tableView = ui->tableView;//выбрать объект tableView
    QSqlTableModel *model = new QSqlTableModel;
    model->setTable("basetable");//в модель помещается таблица из БД
    CheckBoxDelegate *delegate = new CheckBoxDelegate();//создать объекта делегата

    //СПОСОБ 1
    //model->select();

    //СПОСОБ 2, Более предпочтительный!
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);//настраивается редактирование таблицы для внесения значений в столбец
    model->select();
    int countrows=model->rowCount();//кол-во строк
    for (int i=0;isetData(model->index(i, columndelegatenumber),QVariant(0));
    }

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

    void MainWindow::forworktableview(){//получение значения ячейки в tableview через checkbox
    int countrows=ui->tableView->model()->rowCount();

    //Получаем данные
    for (int row =0; row < countrows; ++row) { QModelIndex index = ui->tableView->model()->index(row, columndelegatenumber, QModelIndex());//установка индекса - columndelegatenumber колонка в каждой строке

    QVariant value=ui->tableView->model()->data(index).toBool();//поместить в переменную значение ячейки
    //так как там установлен делегат для checkbox должны быть значения
    //1 - если нажат checkbox и 0 - если не нажат checkbox
    //qDebug() << "информация = " << value; if(value==1){ QModelIndex index1 = ui->tableView->model()->index(row, 0, QModelIndex());//установка индекса - 0 колонка в каждой строке
    QVariant value1=ui->tableView->model()->data(index1);//поместить в переменную значение ячейки
    qDebug() << "выбрано значение = " << value1; //ВАЖНО: //так как данные 0 и 1 сохраняются в БД, в дальнейшем их надо проверять в таблице БД, хотя при удалении, может и не надо } } }


  • В файле дизайнере mainwindow.ui требуется добавить элементы графики pushButton и tableView.

Важные особенности при работе tableView и моделей, работающих с базами данных QSqlQueryModel и QSqlQueryModel

    Внимание:

  • при добавлении колонки в модель с помощью метода insertColumn в этот столбец можно будет вставить какой-либо делегат класса QStyledItemDelegate, но нельзя будет его изменять, так как например для работы с checkbox в ячейках должны храниться данные 0 или 1. Если этих значений в колонке не будет, то и работать делегат не сможет
  • поэтому для добавления делегата нужно создать колонку в самой таблице базы данных и тогда делегат, например checkbox сможет работать полноценно, или же без создания дополнительного столбца в БД выбрать существующее поле с ненужными данными в этот момент, например с порядковыми номерами ID и программно заменить их на нулевые значения, но без сохранения этих чисел в таблице БД!!!
  • если надо вставить данные в таблицу программным методом, режим редактирования должен быть следующим - model->setEditStrategy(QSqlTableModel::OnManualSubmit);