Evgenii Legotckoi
Evgenii LegotckoiТам. 19, 2015, 3:59 Т.Ж.

Qt/C++ - Сабақ 008. QDataWidgetMapper - Виджет арқылы деректер қорымен жұмыс істеу

QDataMapperWidget класы еркін пішінді виджеттегі деректерді көрсету үшін пайдаланылады. Бұл виджет әлі де деректерді көрсету үшін үлгіні қажет етеді.

Мысалы, QSqlTableModel немесе QSqlRelationalTableModel , бірақ деректер енді ауыстырылмайды QTableView ішінде, бірақ әртүрлі ерікті нысандарға. Мысалы, QLineEdit немесе QComboBox. Немесе осы мақалада біз жұмыс істейтін жазбаларды қосу үшін диалогтық терезеде.

Сонымен, тапсырма келесідей. Кестедегі компьютерлер тізімін көрсететін бағдарламаны жазыңыз және әрбір компьютерде үш деректер өрісі болады: Хост атауы, IP мекенжайы және MAC мекенжайы. Сондай-ақ диалогтық терезені шақыру түймесі болуы керек, ол арқылы Кестеге жаңа құрылғы қосуға болады. Біз де сол диалогтық терезе арқылы жазбаларды өңдей алуымыз керек.

Тапсырма сипатталған соң, Qt 5.4.1 негізінде QtCreator 3.3.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 жобасының негізгі терезесінің пішіні Негізгі терезенің пішіні қарапайым болады. Осы пішіннен біз екі нысанды қолданамыз:

  • құрылғы қосу түймесі
  • DeviceTableView

dialogadddevice.ui

Тілқатысу терезесінің пішіні үш QLineEdit өрісін, екі түймені және бір ButtonBox пайдаланады, ол QDialog. сыныбынан мұраланған сынып үшін әдепкі элемент болып табылады.

QDataWidgetMapper тілқатысу терезесі Бізде келесі нысандар жұмыс істейді:

  • HostnameLineEdit
  • IPAddressLineEdit
  • MACLineEdit
  • түймелер жәшігі
  • келесі түймесі
  • алдыңғы түймесі

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();
}

dialogaddevice.h

Жазбаларды қосу және өңдеуге арналған диалогтың тақырып файлы. Тақырып файлынан көріп отырғаныңыздай, модель деректерді ұсыну үшін де пайдаланылады, бірақ оның деректері QTableView түріне аударылмайды, мысалы, QSqlRelationalModel /en/post/67/) оқу құралы немесе осы мақаланың 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

dialogaddevice.cpp

Бұл файл класс логикасын жүзеге асырады. Енгізілген деректердің дұрыстығын тексеру OK түймешігін басқан кезде жүзеге асырылады. Дұрыс толтырылған өрістер жағдайында кестеге жазба енгізіледі немесе ол өңделеді. IP мекенжайы және MAC мекенжайы өрістеріндегі деректерді тексеру Validator көмегімен жүзеге асырылады, оның жазылуы [өткен мақалалардың] бірінде сипатталған (https://evileg. com/en/post/ 56/). Ұқсас деректері бар жазбаның болуын тексеру де жүзеге асырылды.

#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);
}

дерекқор.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

Нәтижесінде, іске қосылған қолданба келесідей болуы керек:

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

Ruslan Polupan
  • Ақп. 13, 2017, 9: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? При редактировании записей никаких вопросов нет а вот при попытке добавления выдает ошибку.
Evgenii Legotckoi
  • Ақп. 13, 2017, 11:33 Т.Ж.

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

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

Ruslan Polupan
  • Ақп. 14, 2017, 1:41 Т.Ж.

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

Evgenii Legotckoi
  • Ақп. 14, 2017, 1:50 Т.Ж.

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

Ruslan Polupan
  • Ақп. 14, 2017, 3:01 Т.Ж.

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

Evgenii Legotckoi
  • Ақп. 14, 2017, 6:57 Т.Ж.

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

t
  • Мамыр 16, 2017, 3:08 Т.Қ.

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

Evgenii Legotckoi
  • Мамыр 16, 2017, 11:51 Т.Қ.
QDialog dialog;
dialog.setModal(true);
dialog.show();
v
  • Ақп. 12, 2018, 9:52 Т.Ж.

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

Evgenii Legotckoi
  • Ақп. 12, 2018, 11: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;
    }
}
v
  • Ақп. 12, 2018, 6:20 Т.Қ.

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

v
  • Ақп. 12, 2018, 7:12 Т.Қ.

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

Evgenii Legotckoi
  • Ақп. 13, 2018, 3:01 Т.Ж.

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

У QTextEdi t есть метод text() который вернёт содержимое поле ввода QTextEdit, это содержимое будет представлено в виде QString, вот её и можно использовать в запросе INSERT.
Evgenii Legotckoi
  • Ақп. 13, 2018, 3:05 Т.Ж.

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

Ваши вопросы на данный момент имеют косвенное отношение к данной статье, поэтому задавайте эти вопросы, пожалуйста, на форуме сайта .
v
  • Ақп. 13, 2018, 7:21 Т.Ж.

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

S
  • Ақп. 15, 2018, 6:25 Т.Ж.

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

bool inserIntoDeviceTable(const QVariantList &data);
Как он используется? просто я не могу найти ни коннекта к нему, ни вызова где то :X
Evgenii Legotckoi
  • Ақп. 15, 2018, 6:32 Т.Ж.

Добрый день!

Вспомогательный класс у меня кочевал из статьи к статье... Поэтому некоторые методы используются не во всех статьях.
Так получилось, что конкретно этот метод не используется в данном примере.
s
  • Ақп. 16, 2018, 5:31 Т.Қ.
  • , а можете подсказать пожалуйста, как выполнить поиск по какой то колонке и выбрать найденную запись?
Evgenii Legotckoi
  • Ақп. 18, 2018, 7:27 Т.Ж.
QDataWidgetMapper работает на основе QSqlTableModel , следовательно вы можете пройтись в цикле по всем строкам модели данных и найти строку с нужными параметрами. Далее получается по номеру строки QModelIndex , который нужно передать в QDataWidgetMapper через метод setCurrentIndex . Тогда вы установить текущей записью нужную Вам строку.
k
  • Наурыз 21, 2018, 8:32 Т.Қ.

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

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

Спасибо!

v
  • Наурыз 31, 2018, 3:47 Т.Ж.

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

Ruslan Polupan
  • Наурыз 31, 2018, 4:21 Т.Ж.

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

Evgenii Legotckoi
  • Наурыз 31, 2018, 8:01 Т.Ж.

Добрый день!

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

a
  • Мамыр 17, 2018, 9:21 Т.Ж.

@EVILEG can you kindly provide a response? Please

Evgenii Legotckoi
  • Мамыр 17, 2018, 4: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.

s
  • Шілде 9, 2019, 4:17 Т.Ж.

А как можно добавить картинку в БД через QDataWidgetMapper? Это делается методом addMapping? Статью про изображение в базе данных я читал.

Evgenii Legotckoi
  • Шілде 9, 2019, 4:41 Т.Ж.

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

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

s
  • Шілде 9, 2019, 8:55 Т.Ж.

Мне просто надо изображение из QLabel'a, расположеннго на диалоговом окне, вставить в БД. Значит, всё-таки это лучше сделать через запрос?

Evgenii Legotckoi
  • Шілде 9, 2019, 9:02 Т.Ж.

Лучше через запрос. Видите ли, если вы будете вставлять изображение в базу данных, там Вам придётся преобразовать данные изображения в BLOB. Как в той статье. А в QDataWidgetMapper такая логика просто отсутсвует. Так что здесь или наследоваться от QDataWidgetMapper и писать свой, или просто через запрос.

Через запрос проще и быстрее. Через наследование уже больше мороки, но в крупных проектах это окупается (В ОЧЕНЬ КРУПНЫХ)

A
  • Мамыр 17, 2020, 12:05 Т.Ж.

Реализовал поиск через QSortFilterProxyModel, но при выборе результата в Mapper передаются значения из tableView по порядку, а не полученные в результате поиска значения. Такая же проблема при сортировке данных в tableView.
Как правильно реализовать поиск?

void dok::on_lineEdit_textChanged(const QString &arg1)
{
    proxySearch = new QSortFilterProxyModel(this);
    proxySearch->setSourceModel(modelIs);
    proxySearch->setFilterCaseSensitivity(Qt::CaseInsensitive);
    proxySearch->setFilterKeyColumn(-1);
    proxySearch->setFilterFixedString(arg1);
    ui->tableView_dok->setModel(proxySearch);
}
Evgenii Legotckoi
  • Мамыр 18, 2020, 3:24 Т.Ж.

Для фильтрации QSqlTableModel нужно использовать метод setFilter у этой самой модели QSqlTableModel. Туда передаётся SQL запрос для where

AB
  • Сәуір 7, 2021, 9:25 Т.Ж.

Начал делать что-то похожее, но без sql.
Не очень понимаю, что делает

mapper->setCurrentModelIndex(model->index(row,0));

Вернее не понимаю вот что: откуда он берёт данные, которые затем подставляет в диалог?

Моё собственное решение (делаю через QStandartItemModel) — передать в конструктор диалога все соответствующие поля из моей таблицы, которые затем через setText() прописать в QLineEdit.
Работать — работает (значения, разумеется, подставляются), но правильно ли так делать?

AB
  • Сәуір 7, 2021, 2:41 Т.Қ.

Понял сам так - происходит через setTable() "Sets the database table on which the model operates to tableName. Does not select data from the table, but fetches its field information", а затем через select() "Populates the model with data from the table that was set via setTable(), using the specified filter and sort condition, and returns true if successful; otherwise returns false".

MP
  • Там. 22, 2021, 1:26 Т.Қ.
  • (өңделген)

Hi EVILEG,

Thnaks for example.
With this example code i am not getting header data. Any idea? I am new to QT and C++.

Can someone please help.

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

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

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

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

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз