© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

Qt/C++ - Урок 008. QDataWidgetMapper - Работа с базой данных через виджет

mapper, QDataWidgetMapper, QDataWidgetMapper example, QSqlTableModel, qt, sql

Для отображения данных в виджет с произвольной формой используется класс QDataMapperWidget . Для работы с этим виджетом по-прежнему требуется модель, для представления данных.

Например, QSqlTableModel или QSqlRelationalTableModel , но данные подставляются уже не в QTableView , а в различные произвольные объекты. Например QLineEdit или QComboBox. Или в диалоговое окно, для добавления записей, с которым поработаем в этой статье.

Итак, задача стоит следующая. Написать программу, которая выводит в таблицу список компьютеров, а каждый компьютер имеет три поля данных: Имя Хоста, IP-адрес и MAC-адрес. Также должна быть кнопка для вызова диалогового окна, через которое Мы можем добавить новое устройство в таблицу. Также у нас должна быть возможность редактирования записей через тоже самое диалоговое окно.

После того, как задача описана, приступаем к её реализации в программном коде, который был написан в QtCreator 3.3.1 на основе Qt 5.4.1.

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

Проект создается как Приложение Qt Widgets, в котором создаются следующие файлы:

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

Примечание. Большую часть интерфейса создаю в дизайнере, чтобы не загромождать логику основного кода лишней информацией. По сути это лишь дело вкуса и привычки.

mainwindow.ui

Форма главного окна проекта QDataWidgetMapper

Формочка главного окна будет простенькой. А пользоваться вы будем из этой формочки двумя объектами:

  • addDeviceButton
  • deviceTableView

dialogadddevice.ui

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

Диалоговое окно QDataWidgetMapper

Имеем в работе следующие объекты:

  • HostnameLineEdit
  • IPAddressLineEdit
  • MACLineEdit
  • buttonBox
  • nextButton
  • previousButton

QDataMapperWidget.pro

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

#-------------------------------------------------
#
# Project created by QtCreator 2015-08-16T23:58:29
#
#-------------------------------------------------

QT       += core
QT       += gui
QT       += sql

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = QDataMapperWidget
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp \
    database.cpp \
    dialogadddevice.cpp

HEADERS  += mainwindow.h \
    database.h \
    dialogadddevice.h

FORMS    += mainwindow.ui \
    dialogadddevice.ui

main.cpp

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

#include "mainwindow.h"
#include <QApplication>

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

    return a.exec();
}

mainwindow.h

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

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSqlTableModel>

#include <database.h>
#include <dialogadddevice.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void on_addDeviceButton_clicked();
    void slotUpdateModels();
    void slotEditRecord(QModelIndex index);

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

private:
    void setupModel(const QString &tableName, const QStringList &headers);
    void createUI();
};

#endif // MAINWINDOW_H

mainwindow.cpp

В файле исходного кода основного окна производим инициализацию таблицы с данными, как было сделано в одной из прошлых статей, к примеру по работе с QSqlTableModel . А также прописываем логику поведения приложения при нажатии кнопки Добавить, которая вызывает диалог добавления записи в таблицу. Также этот диалог вызывается при двойном нажатии на запись в таблице данных. В этом случае в диалог передается информация о том, какая запись была нажата и её данные подставляются в поля для редактирования.

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

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("QDataWidgetMapper Example");
    /* Первым делом необходимо создать объект для работы с базой данных
     * и инициализировать подключение к базе данных
     * */
    db = new DataBase();
    db->connectToDataBase();

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

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

void MainWindow::setupModel(const QString &tableName, const QStringList &headers)
{
    /* Производим инициализацию модели представления данных
     * */
    modelDevice = new QSqlTableModel(this);
    modelDevice->setTable(tableName);
    modelDevice->select();
    /* Устанавливаем названия колонок в таблице с сортировкой данных
     * */
    for(int i = 0, j = 0; i < modelDevice->columnCount(); i++, j++){
        modelDevice->setHeaderData(i,Qt::Horizontal,headers[j]);
    }
}

void MainWindow::createUI()
{
    ui->deviceTableView->setModel(modelDevice);     // Устанавливаем модель на TableView
    ui->deviceTableView->setColumnHidden(0, true);    // Скрываем колонку с id записей
    // Разрешаем выделение строк
    ui->deviceTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    // Устанавливаем режим выделения лишь одно строки в таблице
    ui->deviceTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    // Устанавливаем размер колонок по содержимому
    ui->deviceTableView->resizeColumnsToContents();
    ui->deviceTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->deviceTableView->horizontalHeader()->setStretchLastSection(true);

    connect(ui->deviceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotEditRecord(QModelIndex)));
}

/* Метод для активации диалога добавления записей
 * */
void MainWindow::on_addDeviceButton_clicked()
{
    /* Создаем диалог и подключаем его сигнал завершения работы
     * к слоту обновления вида модели представления данных
     * */
    DialogAddDevice *addDeviceDialog = new DialogAddDevice();
    connect(addDeviceDialog, SIGNAL(signalReady()), this, SLOT(slotUpdateModels()));

    /* Выполняем запуск диалогового окна
     * */
    addDeviceDialog->setWindowTitle(trUtf8("Добавить Устройство"));
    addDeviceDialog->exec();
}

/* Слот обновления модели представления данных
 * */
void MainWindow::slotUpdateModels()
{
    modelDevice->select();
}

/* Метод для активации диалога добавления записей в режиме редактирования
 * с передачей индекса выбранной строки
 * */
void MainWindow::slotEditRecord(QModelIndex index)
{
    /* Также создаем диалог и подключаем его сигнал завершения работы
     * к слоту обновления вида модели представления данных, но передаём
     * в качестве параметров строку записи
     * */
    DialogAddDevice *addDeviceDialog = new DialogAddDevice(index.row());
    connect(addDeviceDialog, SIGNAL(signalReady()), this, SLOT(slotUpdateModel()));

    /* Выполняем запуск диалогового окна
     * */
    addDeviceDialog->setWindowTitle(trUtf8("Редактировать Устройство"));
    addDeviceDialog->exec();
}

dialogadddevice.h

Заголовочный файл диалога добавления и редактирования записей. Как видно по заголовочному файлу, здесь также используется модель для представления данных, но её данные транслируются не в QTableView , как например в уроке по QSqlRelationalModel или в классе MainWindow этой статьи, а в объект класса QDataWidgetMapper. Также здесь переопределяется метод accept(), поскольку прежде чем, закрывать окно, необходимо удостовериться, что данные заполнены верно. В данном проекте критерием правильности заполнения данных является отсутствие дублирующихся записей.

#ifndef DIALOGADDDEVICE_H
#define DIALOGADDDEVICE_H

#include <QDialog>
#include <QSqlTableModel>
#include <QDataWidgetMapper>
#include <QMessageBox>

#include <database.h>

namespace Ui {
class DialogAddDevice;
}

class DialogAddDevice : public QDialog
{
    Q_OBJECT

public:
    explicit DialogAddDevice(int row = -1, QWidget *parent = 0);
    ~DialogAddDevice();

signals:
    void signalReady();

private slots:
    void on_buttonBox_accepted();
    void updateButtons(int row);

private:
    Ui::DialogAddDevice         *ui;
    QSqlTableModel              *model;
    QDataWidgetMapper           *mapper;

private:
    void setupModel();
    void createUI();
    void accept();
};

#endif // DIALOGADDDEVICE_H

dialogadddevice.cpp

В данном файле реализована логика работы класса. Проверка на правильность введённых данных осуществляется в момент нажатия кнопки OK. В случае правильно заполненных полей производится вставка записи в таблицу или её редактирование. Валидация данных в полях IP адрес и MAC адрес производится с помощью Валидатора , написание которого было описано в одной из прошлых статей . Также реализована проверка на существование записи с похожими данными.

#include "dialogadddevice.h"
#include "ui_dialogadddevice.h"

DialogAddDevice::DialogAddDevice(int row, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogAddDevice)
{
    ui->setupUi(this);

    /* Метода для инициализации модели,
     * из которой будут транслироваться данные
     * */
    setupModel();

    /* Если строка не задана, то есть равна -1,
     * тогда диалог работает по принципу создания новой записи.
     * А именно, в модель вставляется новая строка и работа ведётся с ней.
     * */
    if(row == -1){
        model->insertRow(model->rowCount(QModelIndex()));
        mapper->toLast();
    /* В противном случае диалог настраивается на заданную запись
     * */
    } else {
        mapper->setCurrentModelIndex(model->index(row,0));
    }

    createUI();
}

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

/* Метод настройки модели данных и mapper
 * */
void DialogAddDevice::setupModel()
{
    /* Инициализируем модель и делаем выборку из неё
     * */
    model = new QSqlTableModel(this);
    model->setTable(DEVICE);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();

    /* Инициализируем mapper и привязываем
     * поля данных к объектам LineEdit
     * */
    mapper = new QDataWidgetMapper();
    mapper->setModel(model);
    mapper->addMapping(ui->HostnameLineEdit, 1);
    mapper->addMapping(ui->IPAddressLineEdit, 2);
    mapper->addMapping(ui->MACLineEdit, 3);
    /* Ручное подтверждение изменения данных
     * через mapper
     * */
    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);

    /* Подключаем коннекты от кнопок пролистывания
     * к прилистыванию модели данных в mapper
     * */
    connect(ui->previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious()));
    connect(ui->nextButton, SIGNAL(clicked()), mapper, SLOT(toNext()));
    /* При изменении индекса в mapper изменяем состояние кнопок
     * */
    connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(updateButtons(int)));
}

/* Метод для установки валидатора на поле ввода IP и MAC адресов
 * */
void DialogAddDevice::createUI()
{
    QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])";
    QRegExp ipRegex ("^" + ipRange
                     + "\\." + ipRange
                     + "\\." + ipRange
                     + "\\." + ipRange + "$");
    QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this);
    ui->IPAddressLineEdit->setValidator(ipValidator);

    QString macRange = "(?:[0-9A-Fa-f][0-9A-Fa-f])";
    QRegExp macRegex ("^" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange + "$");
    QRegExpValidator *macValidator = new QRegExpValidator(macRegex, this);
    ui->MACLineEdit->setValidator(macValidator);
}

void DialogAddDevice::on_buttonBox_accepted()
{
    /* SQL-запрос для проверки существования записи
     * с такими же учетными данными.
     * Если запись не существует или находится лишь индекс
     * редактируемой в данный момент записи,
     * то диалог позволяет вставку записи в таблицу данных
     * */
    QSqlQuery query;
    QString str = QString("SELECT EXISTS (SELECT " DEVICE_HOSTNAME " FROM " DEVICE
                          " WHERE ( " DEVICE_HOSTNAME " = '%1' "
                          " OR " DEVICE_IP " = '%2' )"
                          " AND id NOT LIKE '%3' )")
            .arg(ui->HostnameLineEdit->text(),
                 ui->IPAddressLineEdit->text(),
                 model->data(model->index(mapper->currentIndex(),0), Qt::DisplayRole).toString());

    query.prepare(str);
    query.exec();
    query.next();

    /* Если запись существует, то диалог вызывает
     * предупредительное сообщение
     * */
    if(query.value(0) != 0){
        QMessageBox::information(this, trUtf8("Ошибка хоста"),
                                 trUtf8("Хост с таким именем или IP-адресом уже существует"));
    /* В противном случае производится вставка новых данных в таблицу
     * и диалог завершается с передачей сигнала для обновления
     * таблицы в главном окне
     * */
    } else {
        mapper->submit();
        model->submitAll();
        emit signalReady();
        this->close();
    }
}

void DialogAddDevice::accept()
{

}

/* Метод изменения состояния активности кнопок пролистывания
 * */
void DialogAddDevice::updateButtons(int row)
{
    /* В том случае, если мы достигаем одного из крайних (самый первый или
     * самый последний) из индексов в таблице данных,
     * то мы изменяем состояние соответствующей кнопки на
     * состояние неактивна
     * */
    ui->previousButton->setEnabled(row > 0);
    ui->nextButton->setEnabled(row < model->rowCount() - 1);
}

database.h

Вспомогательный класс для работы с базой данных является видоизменённым вариантом этого же класса из прошлых уроков.

#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_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_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_HOSTNAME ", "
                                              DEVICE_IP ", "
                                              DEVICE_MAC " ) "
                  "VALUES (:Hostname, :IP, :MAC )");
    query.bindValue(":Hostname",    data[0].toString());
    query.bindValue(":IP",          data[1].toString());
    query.bindValue(":MAC",         data[2].toString());
    // После чего выполняется запросом методом exec()
    if(!query.exec()){
        qDebug() << "error insert into " << DEVICE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    }
    return false;
}

Итог

Архив с исходниками: QDataWidgetMapper

В результате работающее приложение должно выглядеть следующим образом:

Комментарии

13 февраля 2017 г. 14:52

Вопрос: Как записать данные в столбец который не привязан к элементу ввода в форме? Например в таблице

CREATE TABLE objects (
    object_id       INT(10) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
    brend_id        INT(10) unsigned NOT NULL,
    terminal_id     INT(10) unsigned NOT NULL,
    region_id       INT(10) unsigned NOT NULL,
    name            VARCHAR(100) NOT NULL,
    phone           VARCHAR(100)
);
привязаны к lineedit все поля кроме object_id и brend_id. object id это автоинкремент с ним все понятно подставляется значение по умолчанию. Как с используя QDataWidgetMapper записывать определенное значение в brend_id? При редактировании записей никаких вопросов нет а вот при попытке добавления выдает ошибку.
13 февраля 2017 г. 16:33

Либо добавить в форум соответствующий виджет и сделать его скрытым через setVisible(false) , либо написать собственный маппер, в котором некоторые поля будут обрабатываться внутри маппера по заданному алгоритму. Я изучал вопрос маппера в QML, вот статья на эту тему , но там не для QSqlTableModel , а просто для модели данных.

Если делать со скрытым виджетом, то следует отслеживать сигнал currentIndexChanged и уже по нему обрабатывать требуемые скрытые виджеты так, как требуется. В документации нет и намёка на работу со скрытыми полями каким-либо документированным способом, поэтому вариант со скрытыми виджетами видится мне наиболее адекватным.

Для Django рекомендую VDS-хостинг TIMEWEB

14 февраля 2017 г. 6:41

Про скрытый виджет идея пришла сразу, но думал что есть другие варианты.

14 февраля 2017 г. 6:50

Увы, но других вариантов я не вижу. QDataWidgetMapper явно подходит только для этого, иначе был бы какой-нибудь класс держатель значений. Но тот же самый QVariant, что наиболее близкое по смыслу, здесь явно не подходит. Так что... только скрытый виджет.

Для Django рекомендую VDS-хостинг TIMEWEB

14 февраля 2017 г. 8:01

Успешно заработало :-)

14 февраля 2017 г. 11:57

Ну и отлично :-)

Для Django рекомендую VDS-хостинг TIMEWEB

16 мая 2017 г. 19:08

Как сделать так, что бы когда я открываю диалог, я не могу ничего делать в программе, пока я не закрою сам диалог? (Я не заметил(плохо прочел код))

17 мая 2017 г. 3:51
QDialog dialog;
dialog.setModal(true);
dialog.show();

Для Django рекомендую VDS-хостинг TIMEWEB

12 февраля 2018 г. 14:52

Очень долго искал подобное описание.Спасибо. Только подскажи пожалуйста, как можно реализовать удаление строки с помощью кнопки

12 февраля 2018 г. 16:12

Нужно навешать слот на клик кнопки

connect(ui->removeButton, &QPushButton::clicked, this, &MapperDialog::slotForRemove);
В этом слоте нужно достать id записи и по этому id удалить из базы данных запись, для этого можно реализовать вспомогательный метод в классе DataBase, который будет работать с QSqlQuery
bool DataBase::removeRecord(const int id)
{
    // Удаление строки из базы данных будет производитсья с помощью SQL-запроса
    QSqlQuery query;
 
    // Удаление производим по id записи, который передается в качестве аргумента функции
    query.prepare("DELETE FROM " TABLE " WHERE id= :ID ;");
    query.bindValue(":ID", id);
// Выполняем удаление
    if(!query.exec()){
        qDebug() << "error delete row " << TABLE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    }
}

Для Django рекомендую VDS-хостинг TIMEWEB

12 февраля 2018 г. 23:20

И еще, как можно из диалогового окна, из QTextEdit , передать данные в таблицу?

13 февраля 2018 г. 0:12

Спасибо большое, но немного не пойму, что именно нужно прописать в слоте, что бы получать id и удалять через кнопку

13 февраля 2018 г. 8:01

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

У QTextEdi t есть метод text() который вернёт содержимое поле ввода QTextEdit, это содержимое будет представлено в виде QString, вот её и можно использовать в запросе INSERT.

Для Django рекомендую VDS-хостинг TIMEWEB

13 февраля 2018 г. 8:05

Можете в Mapper`e прикрутить ещё одно поле ввода, которое будет выводить id записи. Поле ввода можете настроить в режим readOnly, чтобы его нельзя было редактировать. Тогда сможете забирать через метод text() или value() данный id записи.

Ваши вопросы на данный момент имеют косвенное отношение к данной статье, поэтому задавайте эти вопросы, пожалуйста, на форуме сайта .

Для Django рекомендую VDS-хостинг TIMEWEB

13 февраля 2018 г. 12:21

Хорошо, спасибо большое за помощь

15 февраля 2018 г. 11:25

Evileg, Здравствуйте. Можете пожалуйста пояснить, вот есть метод:

bool inserIntoDeviceTable(const QVariantList &data);
Как он используется? просто я не могу найти ни коннекта к нему, ни вызова где то :X
15 февраля 2018 г. 11:32

Добрый день!

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

Для Django рекомендую VDS-хостинг TIMEWEB

16 февраля 2018 г. 22:31
  • , а можете подсказать пожалуйста, как выполнить поиск по какой то колонке и выбрать найденную запись?
18 февраля 2018 г. 12:27
QDataWidgetMapper работает на основе QSqlTableModel , следовательно вы можете пройтись в цикле по всем строкам модели данных и найти строку с нужными параметрами. Далее получается по номеру строки QModelIndex , который нужно передать в QDataWidgetMapper через метод setCurrentIndex . Тогда вы установить текущей записью нужную Вам строку.

Для Django рекомендую VDS-хостинг TIMEWEB

22 марта 2018 г. 0:32

А где находится связь между нажатием на кнопку "ok" и выполнением слота

on_addDeviceButton_clicked? В форме dialogadddevice.ui её тоже вроде бы нет. и не понятна надобность перегрузки слота DialogAddDevice::accept().
22 марта 2018 г. 8:19
on_addDeviceButton_clicked добавляется через графический дизайнер, а подключение этого слота осуществляется по его имени в автоматически генерируемом файле ui_dialogadddevice.h. С перегрузкой метода accept() скорее мой недосмотр, сначала хотел использовать этот метод, а потом всё-таки воспользовался слотом on_addDeviceButton_clicked , а код до конца не подчистил, но как именно это происходило... уже не помню.

Для Django рекомендую VDS-хостинг TIMEWEB

23 марта 2018 г. 14:32

Спасибо!

31 марта 2018 г. 7:47

Здравствуйте! В этой статье и нескольких Ваших других заметил метод closeDataBase(), но не нашел чтобы он использовался. И вообще во многих источниках видел исходники без закрытия БД. В php обычно (всегда) после запроса(ов) БД закрывается, и выходит здесь (в qt c++) также такое предусмотрено, но не совсем ясно понял когда и где его нужно (целесообразно) использовать? Как быть, если программа обращается к БД редко единичным образом или же когда все время требуется соединение и частые обращения?

31 марта 2018 г. 8:21

В Qt После создания соединения с БД оно хранится на протяжения работы с приложением, но не постоянно. Необходимости закрывать соединение особо нет.

31 марта 2018 г. 12:01

Добрый день!

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

Для Django рекомендую VDS-хостинг TIMEWEB

8 мая 2018 г. 13:29
Thanks for the article.
I've been working around a problem with Qt/C++ for quite a while now
and I can't seem to find a solution neither in the official Qt documentation or in StackOverflow.
I'd like to show a QCheckBox with an associated text inside a general QWidget (say e.g. QComboBox), while also storing
their state in a model, using the Model/View paradigm.
Note that I obviously know how to create a QCheckBox with text (QCheckBox* checkBox = new QCheckBox(text);), and
that I have subclassed QAbstractTableModel in my custom model. The columns of the model are two: a QString for the
text associated with the checkbox and a bool to identify the checkbox status (checked/unchecked which gets mapped to Qt::Checked and Qt::Unchecked).
I already have a QList containing 4 labels to show with their "checked" status (which is, by default, unchecked).
I have already stumbled upon QDataWidgetMapper, but I don't think it suit my needs,
since I need to display a finite amount of rows at once, and I don't need to have "previous" and "next" functionality
like in the official example (http://doc.qt.io/qt-5/qtwidgets-itemviews-combowidgetmapper-example.html). But maybe I'm misunderstanding the power of QDataWidgetMapper.
Can you please help me understand what to do?

17 мая 2018 г. 13:21

@EVILEG can you kindly provide a response? Please

17 мая 2018 г. 20:22

If you want to show two columns from your model in combobox, then, I think, you can try to set Model in QComboBox and use custom ItemDelegate for QComboBox. Try to research information about delegates in official documentation.

Для Django рекомендую VDS-хостинг TIMEWEB

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
15 октября 2018 г. 21:36
Allyans .

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

  • Результат 60баллов,
  • Очки рейтинга-1
15 октября 2018 г. 11:25
Екатерина Самойлова

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

  • Результат 33баллов,
  • Очки рейтинга-10
15 октября 2018 г. 11:17
Екатерина Самойлова

C++ - Тест 006. Перечисления

  • Результат 80баллов,
  • Очки рейтинга4
Последние комментарии
17 октября 2018 г. 8:43
pasagir

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Не получается bool DataBase::insertDataIntoDB(QVariantList data){ QSqlQuery query(db); QString str; qDebug()<<"InsertInsertInsertInsertInsert"<<QThread::curre...
17 октября 2018 г. 7:09
Евгений Легоцкой

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Попробуйте передать инстанс базы данных в конструктор QSqlQuery QSqlQuery q(db);
16 октября 2018 г. 16:14
pasagir

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

В Qt 5.11. при попытке вставить в БД запись выдает ошибку QSqlQuery::prepare: database not openQSqlDatabasePrivate::database: requested database does not belong to the calling thread. ...
10 октября 2018 г. 9:50
Евгений Легоцкой

Qt/C++ - Урок 083. Создание динамической библиотеки и подключение её в другой проект

Если и начинать писать о плагинах, то нужно тогда с Qt Creator начинать, там наверняка будет одинаковый принцип, но по Qt Creator хотя бы информация есть.
Сейчас обсуждают на форуме
17 октября 2018 г. 16:33
Allyans .

Работа с WinAPI в QT(изменение title bar)

Здравствуйте. Я хочу в своей программе изменить цвет title bar. Так как в qt нет не каких функций связаных с этим я искал в интернете ответ на мой вопрос и там советовали функцию SetSysColors(...
17 октября 2018 г. 13:39
Михаиллл

Настройка Qt Creator для Android

Здравствуйте. У меня установлены SDK, NDK. Но для компилятора не хватает arm-linux-android-elf-64bit, 86-linux-android-elf-64bit . Скажите пожалуйста как это исправить?
15 октября 2018 г. 12:45
Allyans .

QGraphicsItem change color

Хорошо)
11 октября 2018 г. 10:13
Arrow

Работа с WebView в QML

Нашел в чем проблема. Пишу на случай если кому-то попадется такое же счастье с WebView как и мне. Проблема как оказалась с Debug версией, так как в Release и Profile все работает (...
10 октября 2018 г. 12:49
Виталий Антипов

Кто что делает на Qt?

Работаем по локальной сети. Файл базы, схемы и фото лежат на сервере. Чтобы не было проблем при одновременной работе с одним файлом, все запросы обернул в транзакции, как указано в документаци...
Присоединяйтесь к нам в социальных сетях