Реклама

Qt/C++ - Урок 015. QTableWidget или Как сделать таблицу с чекбоксами

РуководствоQtQt, Qt Таблица, QTableWidget, QTableWidget example, QTableWidget пример8816

Использование QTableWidget будет первым способом, который посоветуют Вам для создания таблиц с чекбоксами на Qt. Поэтому давайте рассмотрим и этот вариант работы с таблицами в Qt и конечно же применим чекбоксы.

Итак, чтобы урок был более приближен к реальности, захватим немного программного кода из урока по QDataWidgetMapper . А именно возьмём класс для работы с базой данных, чтобы уж сразу делать таблицу из базы данных. После чего сделаем форму главного окна приложения и выведем данные из таблицы с отображением чекбоксов. Естественно, при включении приложения таблица база данных будет создана и заполнена несколькими записями, которые мы и будем выводить в виджет.

Программный код был написан в QtCreator 3.3.1 на основе Qt 5.4.1.

Структура проекта для QTableWidget

Предлагаю ознакомиться со структурой проекта:

  • QTableWidgetExample.pro - профайл;
  • mainwindow.h - заголовочный файл основного окна приложения;
  • mainwindow.cpp - исходный код окна;
  • main.cpp - основной исходный файл, с которого стартует приложение;
  • mainwindow.ui - формочка основного окна приложения;
  • database.h - заголовочный файл вспомогательного класса, применяющегося для работы с информацией, которая помещена в базу данных;
  • database.cpp - исходный файл вспомогательного класса, применяющегося для работы с информацией, которая помещена в базу данных;

mainwindow.ui

Всё, что Вам нужно сделать с этим файлом, это кинуть в форму главного окна в дизайнере QTableWidget.

mainwindow.h

В данном файле объявляется объект базы данных, с которым мы будем работать, а также метод для заполнения данными QTableWidget.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSqlQuery>

/* My includes */
#include <database.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow  *ui;
    DataBase        *db;

private:
    /* Метод для настройки интерфейса,
     * в данном методе будет выполняться заполнение QTableWidget
     * записями из таблицы
     * */
    void createUI(const QStringList &headers);
};

#endif // MAINWINDOW_H

mainwindow.cpp

В этом файле заключена цель всего урока, а именно настройка QTableWidget и заполнение его записями из базы данных.

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->setWindowTitle("QTableWidget Example");
    /* Первым делом необходимо создать объект для работы с базой данных
     * и инициализировать подключение к базе данных
     * */
    db = new DataBase();
    db->connectToDataBase();

    /* Наполним базу данных записями */
    for(int i = 1; i < 5; i++){
        /* Вставляем запись в таблицу, сразу устанавливаем состояние чекбокса.
         * Если устройство имеет нечётный номер, то статус чекбокса true,
         * иначе false
         * */
        db->inserIntoDeviceTable(QVariantList() << QString::number(i & 1)
                                                << "Device " + QString::number(i)
                                                << "192.168.0." + QString::number(i)
                                                << "AA:AA:AA:AA:AA:A" + QString::number(i));
    }

    /* Настраиваем внешний вид таблицы
     * с заданием названий колонок, а также
     * Заполняем таблицу записями из базы данных
     * */
    this->createUI(QStringList() << trUtf8("id")
                                 << trUtf8("Нечетность")
                                 << trUtf8("Имя компьютера")
                                 << trUtf8("IP адрес")
                                 << trUtf8("MAC адрес")
               );
}

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

/* Метод для настройки интерфейса,
 * в данном методе будет выполняться заполнение QTableWidget
 * записями из таблицы
 * */
void MainWindow::createUI(const QStringList &headers)
{
    ui->tableWidget->setColumnCount(5); // Указываем число колонок
    ui->tableWidget->setShowGrid(true); // Включаем сетку
    // Разрешаем выделение только одного элемента
    ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
    // Разрешаем выделение построчно
    ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    // Устанавливаем заголовки колонок
    ui->tableWidget->setHorizontalHeaderLabels(headers);
    // Растягиваем последнюю колонку на всё доступное пространство
    ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
    // Скрываем колонку под номером 0
    ui->tableWidget->hideColumn(0);

    // Создаём запрос для для выборки записей из базы данных
    QSqlQuery query("SELECT "
                    DEVICE ".id, "
                    DEVICE "." DEVICE_CHECK_STATE ", "
                    DEVICE "." DEVICE_HOSTNAME ", "
                    DEVICE "." DEVICE_IP ", "
                    DEVICE "." DEVICE_MAC
                    " FROM " DEVICE);

    /* Выполняем заполнение QTableWidget записями с помощью цикла
     * */
    for(int i = 0; query.next(); i++){
        // Вставляем строку
        ui->tableWidget->insertRow(i);
        /* Устанавливаем в первую колонку id забирая его из результата SQL-запроса
         * Эта колонка будет скрыта
         * */
        ui->tableWidget->setItem(i,0, new QTableWidgetItem(query.value(0).toString()));

        // Создаём элемент, который будет выполнять роль чекбокса
        QTableWidgetItem *item = new QTableWidgetItem();
        item->data(Qt::CheckStateRole);
        /* Проверяем, на статус нечетности, если нечетное устройство, то
         * выставляем состояние чекбокса в Checked, иначе в Unchecked
         * */
        if(query.value(1).toInt() == 1){
            item->setCheckState(Qt::Checked);
        } else {
            item->setCheckState(Qt::Unchecked);
        }
        // Устанавливаем чекбокс во вторую колонку
        ui->tableWidget->setItem(i,1, item);
        // Далее забираем все данные из результата запроса и устанавливаем в остальные поля
        ui->tableWidget->setItem(i,2, new QTableWidgetItem(query.value(2).toString()));
        ui->tableWidget->setItem(i,3, new QTableWidgetItem(query.value(3).toString()));
        ui->tableWidget->setItem(i,4, new QTableWidgetItem(query.value(4).toString()));
    }

    // Ресайзим колонки по содержимому
    ui->tableWidget->resizeColumnsToContents();
}

database.h

Данный файл отличается от того, что был взят из урока по QDataWidgetMapper тем, что была добавлена define директива для чекбокса, соответственно это повлекло изменение методов в файле database.cpp. А именно insertIntoDeviceTable и createDeviceTable.

#ifndef DATABASE_H
#define DATABASE_H

#include <QObject>
#include <QSql>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlDatabase>
#include <QFile>
#include <QDate>
#include <QDebug>

/* Директивы имен таблицы, полей таблицы и базы данных */
#define DATABASE_HOSTNAME   "ExampleDataBase"
#define DATABASE_NAME       "DataBase.db"

#define DEVICE                  "DeviceTable"
#define DEVICE_CHECK_STATE      "CheckState"
#define DEVICE_HOSTNAME         "Hostname"
#define DEVICE_IP               "IP"
#define DEVICE_MAC              "MAC"

class DataBase : public QObject
{
    Q_OBJECT
public:
    explicit DataBase(QObject *parent = 0);
    ~DataBase();
    /* Методы для непосредственной работы с классом
     * Подключение к базе данных и вставка записей в таблицу
     * */
    void connectToDataBase();
    bool inserIntoDeviceTable(const QVariantList &data);

private:
    // Сам объект базы данных, с которым будет производиться работа
    QSqlDatabase    db;

private:
    /* Внутренние методы для работы с базой данных
     * */
    bool openDataBase();
    bool restoreDataBase();
    void closeDataBase();
    bool createDeviceTable();
};

#endif // DATABASE_H

database.cpp

#include "database.h"

DataBase::DataBase(QObject *parent) : QObject(parent)
{

}

DataBase::~DataBase()
{

}

/* Методы для подключения к базе данных
 * */
void DataBase::connectToDataBase()
{
    /* Перед подключением к базе данных производим проверку на её существование.
     * В зависимости от результата производим открытие базы данных или её восстановление
     * */
    if(!QFile("C:/example/" DATABASE_NAME).exists()){
        this->restoreDataBase();
    } else {
        this->openDataBase();
    }
}

/* Методы восстановления базы данных
 * */
bool DataBase::restoreDataBase()
{
    if(this->openDataBase()){
        if(!this->createDeviceTable()){
            return false;
        } else {
            return true;
        }
    } else {
        qDebug() << "Не удалось восстановить базу данных";
        return false;
    }
    return false;
}

/* Метод для открытия базы данных
 * */
bool DataBase::openDataBase()
{
    /* База данных открывается по заданному пути
     * и имени базы данных, если она существует
     * */
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setHostName(DATABASE_HOSTNAME);
    db.setDatabaseName("C:/example/" DATABASE_NAME);
    if(db.open()){
        return true;
    } else {
        return false;
    }
}

/* Методы закрытия базы данных
 * */
void DataBase::closeDataBase()
{
    db.close();
}

/* Метод для создания таблицы устройств в базе данных
 * */
bool DataBase::createDeviceTable()
{
    /* В данном случае используется формирование сырого SQL-запроса
     * с последующим его выполнением.
     * */
    QSqlQuery query;
    if(!query.exec( "CREATE TABLE " DEVICE " ("
                            "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                            DEVICE_CHECK_STATE " INTEGER       NOT NULL,"
                            DEVICE_HOSTNAME  " VARCHAR(255)    NOT NULL,"
                            DEVICE_IP        " VARCHAR(16)     NOT NULL,"
                            DEVICE_MAC       " VARCHAR(18)     NOT NULL"
                        " )"
                    )){
        qDebug() << "DataBase: error of create " << DEVICE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    }
    return false;
}

/* Метод для вставки записи в таблицу устройств
 * */
bool DataBase::inserIntoDeviceTable(const QVariantList &data)
{
    /* Запрос SQL формируется из QVariantList,
     * в который передаются данные для вставки в таблицу.
     * */
    QSqlQuery query;
    /* В начале SQL запрос формируется с ключами,
     * которые потом связываются методом bindValue
     * для подстановки данных из QVariantList
     * */
    query.prepare("INSERT INTO " DEVICE " ( " DEVICE_CHECK_STATE ", "
                                              DEVICE_HOSTNAME ", "
                                              DEVICE_IP ", "
                                              DEVICE_MAC " ) "
                  "VALUES (:CheckState, :Hostname, :IP, :MAC )");
    query.bindValue(":CheckState",  data[0].toInt());
    query.bindValue(":Hostname",    data[1].toString());
    query.bindValue(":IP",          data[2].toString());
    query.bindValue(":MAC",         data[3].toString());
    // После чего выполняется запросом методом exec()
    if(!query.exec()){
        qDebug() << "error insert into " << DEVICE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    }
    return false;
}

Итог

В результате при запуске программы будет создано приложение, в котором будет таблица с четырьмя записями, две из которых будут с отмеченными чекбоксами.

Пример приложения с QTableWidget
Реклама

Комментарии

Спасибо за статью, не подскажите  как можно использовать отмеченные чек боксом строчки. Мне их нужно скопировать их в другой QTableWidgetItem ?

Ответил на форуме .

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
  • BoostEX
  • 17 августа 2017 г. 16:45

C++ - Тест 001. Первая программа и типы данных

  • Результат - 73 баллов
  • Nordman
  • 15 августа 2017 г. 20:40

C++ - Тест 005. Структуры и Классы

  • Результат - 66 баллов

C++ - Тест 002. Константы

  • Результат - 33 баллов
Последние комментарии
  • EVILEG
  • 17 августа 2017 г. 18:33

Qt/C++ - Урок 069. Шифрование методом XOR

Не обратил внимания на это, Проверял с большим текстом.. По идее не должно.

Qt/C++ - Урок 069. Шифрование методом XOR

Шифрует/дешифрует текст от 8 символов, так и должно быть?

  • EVILEG
  • 15 августа 2017 г. 20:32

Qt/C++ - Урок 048. QThread - работа с потоками с помощью moveToThread

Нууу... тут уже вопрос к самому Qt4.8. Если честно, идей нет, да и копаться в deprecated коде желания тоже нет.

  • t000r
  • 15 августа 2017 г. 19:49

Qt/C++ - Урок 048. QThread - работа с потоками с помощью moveToThread

В qt5.6 всё нормально заработало. С 4.8 - нет

  • EVILEG
  • 15 августа 2017 г. 17:44

Qt/C++ - Урок 050. Логирование событий Qt приложения в текстовый файл

Я полистал информацию в интернетах, вроде как кто-то пытается подружить его с Qt5, но успешных результатов не нашёл. Да и на сайте как-то не заметно информации о том, что конкретно ему нужно, ...

Сейчас обсуждают на форуме
  • EVILEG
  • 19 августа 2017 г. 17:47

Проблемы с памятью

Добрый день! При работе со StackView, когда вы делаете push страниц, они постоянно добавляются и добавляются. Они не должны в данном случае удаляться, если вы просто пушите страницы в Sta...

  • MinusNol
  • 18 августа 2017 г. 16:22

WINAPI и Qt.

Да, покопаюсь. С WINAPI плохо знаком :) Но я уже существенно улучшил свой код благодаря вашему совету, благодарю вас :)

  • alex_lip
  • 18 августа 2017 г. 13:50

Я только учусь..(как правильно присвоить значение объекту другого класса)

хм. Похоже файл где-то в кэше остался. Я его второй раз  не прикреплял.

Сборка Qt / C++ проекта под windows и linux

нет, я тут кое что попробую- о результатах скажу)))

  • EVILEG
  • 16 августа 2017 г. 13:38

Перевод кодировки строки из windows 1251 в Utf-8

Здесь необходимо использовать QTextCodec. Вещь это очень хитрая в том плане, что объект этого класса необходимо создавать с определённой кодировкой. Поскольку он будет гонять данные от заданной код...