© 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 и уже по нему обрабатывать требуемые скрытые виджеты так, как требуется. В документации нет и намёка на работу со скрытыми полями каким-либо документированным способом, поэтому вариант со скрытыми виджетами видится мне наиболее адекватным.

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

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

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

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

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

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

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

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

16 мая 2017 г. 19:08

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

17 мая 2017 г. 3:51
QDialog dialog;
dialog.setModal(true);
dialog.show();
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;
    }
}
12 февраля 2018 г. 23:20

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

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

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

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

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

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

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

Ваши вопросы на данный момент имеют косвенное отношение к данной статье, поэтому задавайте эти вопросы, пожалуйста, на форуме сайта .
13 февраля 2018 г. 12:21

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

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

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

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

Добрый день!

Вспомогательный класс у меня кочевал из статьи к статье... Поэтому некоторые методы используются не во всех статьях.
Так получилось, что конкретно этот метод не используется в данном примере.
16 февраля 2018 г. 22:31
  • , а можете подсказать пожалуйста, как выполнить поиск по какой то колонке и выбрать найденную запись?
18 февраля 2018 г. 12:27
QDataWidgetMapper работает на основе QSqlTableModel , следовательно вы можете пройтись в цикле по всем строкам модели данных и найти строку с нужными параметрами. Далее получается по номеру строки QModelIndex , который нужно передать в QDataWidgetMapper через метод setCurrentIndex . Тогда вы установить текущей записью нужную Вам строку.
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 , а код до конца не подчистил, но как именно это происходило... уже не помню.
23 марта 2018 г. 14:32

Спасибо!

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

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

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

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

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

Добрый день!

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

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
14 августа 2018 г. 11:29
Марк Федяшов

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат 70баллов,
  • Очки рейтинга1
14 августа 2018 г. 11:05
Марк Федяшов

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат 50баллов,
  • Очки рейтинга-4
14 августа 2018 г. 11:00
Марк Федяшов

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

  • Результат 42баллов,
  • Очки рейтинга-8
Последние комментарии
10 августа 2018 г. 13:40
Alex

Работа с триггерными функциями в PostgreSQL

Приветствую! Если вы создаете новую таблицу, почему бы просто не сделать вьюху ? Просто от одного названия "триггер" как-то не хочется его использовать, а уж кода сколько писа...
10 августа 2018 г. 11:46
Евгений Легоцкой

Bash скрипт для создания и скачивания дампа базы данных и медиа файлов с удаленного сервера

Вон оно что. Не сталкивался с таким, надо будет глянуть исходники дефолтного менеджера объектов. Возможно там кеширование просто. Пробовали добавить запись через adminer, перезапусти...
10 августа 2018 г. 11:34
Alex

Bash скрипт для создания и скачивания дампа базы данных и медиа файлов с удаленного сервера

допустим у нас есть любая таблица, созданная джангой. через админку добавляем пару записей. все ок. далее, лично в моем случае , я открываю adminer, и в эту таблицу добавляю еще одну зап...
Сейчас обсуждают на форуме
14 августа 2018 г. 7:02
Ruslan-maniak

Переключение страниц и перевод фокуса на потомка новой страницы

Большое спасибо. Подтолкнули меня на мысль вынести обработку клавиш из PathView на всю страницу. И тогда - да, ваша подсказка работает. добавил в StackView onCurrentItemChanged: currentItem.fo...
14 августа 2018 г. 6:39
Евгений Легоцкой

Как сделать аудиовизуализацию для плеера на qt?

Добрый день. Просмотрите пример в Qt Creator, который на QML, там реализовано визуализация, возможно вам понравится использовать, QML, да и кастомные интерфейсы на нём всё-таки лучше...
11 августа 2018 г. 10:12
Евгений Легоцкой

Qt C++ vs QML

Добрый день. Если Андроид предполагается, то конечно нужно использовать QML. Я занимался разработкой арканоида на QML и ещё одной игры. Пытался реализовывать логику на QML, но это ...
11 августа 2018 г. 9:24
Евгений Легоцкой

Помогите со слоями

Проверочное сообщение
9 августа 2018 г. 13:27
Иринка Садыкова

как выделять текст мышкой в qml ?

я ведь использую те же средства. единственное отличие -  ввожу текст с клавиатуры в TextArea

Рекомендуемые страницы