QTableWidget пайдалану сізге Qt ішінде құсбелгілері бар кестелер жасаудың бірінші жолы болады. Сондықтан Qt кестелерімен жұмыс істеу үшін осы опцияны қарастырайық және, әрине, құсбелгілерді қойыңыз.
Сонымен, сабақты шындыққа жақындату үшін QDataWidgetMapper сайтындағы сабақтан бағдарлама кодын алайық. Дәлірек айтқанда, дерекқордан кестені дереу жасау үшін мәліметтер қорымен жұмыс істеу класын алайық. Осыдан кейін біз қосымшаның негізгі терезесінің пішінін жасаймыз және құсбелгілер қойылған кестедегі деректерді көрсетеміз. Әрине, қолданбаны қосқанда, дерекқор кестесі жасалады және біз виджетте көрсететін бірнеше жазбалармен толтырылады.
Код Qt 5.4.1 негізінде QtCreator 3.3.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(); }
дерекқор.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; }
Барлығы
Нәтижесінде, бағдарлама іске қосылғанда, төрт жазбасы бар кесте болатын қосымша жасалады, оның екеуінде құсбелгілер қойылады.
Спасибо за статью, не подскажите как можно использовать отмеченные чек боксом строчки. Мне их нужно скопировать их в другой QTableWidgetItem ?
Ответил на форуме .
В файле mainwindow.cpp строка 86:
item->data(Qt::CheckStateRole); // без слов
ну да, затесался неудалённый кусок ерунды, надо будет отредактировать на досуге статью.
Доброго времени суток.
Возник вопрос по статье.
Как организовать сортировку по столбцу с CheckBox.
Т.е. чтобы отмеченные строки отображались в верхней части TableWidget.
Дополнительный скрытый столбец делать или есть еще варианты?
Добрый день. Добавьте ORDER BY в заппрос SELECT по столбцу с чекбоксами.
Дело в том что чтолбец с чекбоксами никак не связан с базой. Он только для выбора объектов.
На ум приходит несколько вариантов:
Можно конечно, как-то написать костыли на изменение позиций строчек при наличии выделенного чекбокса, но это будут костыли. Лучше уж перейти на полноценную модель данных в данном случае и QTableView
Попробовал запустить код, описанный в данной статье, но получаю следующее:
Подскажите в чем может быть проблема ?
Вывод окна - пустой:
Пока добавляли у себя код, что-то пробовали проверяли, могло дойти до ситуации, когда у вас получилась создана таблица, с количеством колонок, не совпадающим с количеством колонок в финальной версии. В общем в INSERT запросе у вас больше или меньше аргументов, чем колонок в таблице DEVICE по факту.
Да, у меня тоже такая мысль возникла, но я просто скопипастил этот код из статьи, ничего в нем не меняя.
Кажется я понял в чем ошибка - я вручную создал таблицу Device в базе данных DataBase.db через DB Browser for SQLite в корне проекта с соответствующими типами данных и по какой-то причине insert не выполнялся, как только БД удалил, пример заработал.
Кто-нибудь знает, как сделать так, чтобы в QTableWidget состоящей из чекбоксов в строке таблицы можно было выбрать только один checkbox ?
ошибки куда-то пропали, но база данных не заполняется