Qt/C++ - Lesson 008. QDataWidgetMapper - Working with the database via a widget

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

To display the data in a widget with an arbitrary use QDataMapperWidget class. To work with this widget is still required model for presentation.

For example, QSqlTableModel or QSqlRelationalTableModel , but the data is not already substituted QTableView , and various arbitrary objects. For example QLineEdit or QComboBox . Or in the dialog box to add records with which to work in this article.

Thus, the problem is as follows. Write a program that displays a list of computers in the table, and each computer has three data fields: Имя Хоста, IP-адрес и MAC-адрес. There should also be a button to display the dialog box, through which we can add a new device to the table. Also, we should be able to edit the records through the same dialog box.

Project structure of QDataWidgetMapper

The project is created as an application Qt Widgets, where the following files are created:

  • QDataMapperWidget.pro ;
  • mainwindow.h - header file of the main application window;
  • mainwindow.cpp - source code of window;
  • main.cpp - the main source file from which the application starts;
  • mainwindow.ui - form of the main application window;
  • database.h - header file of helper class to be used for information that is placed in a database;
  • database.cpp - source code of helper class file to be used for information that is placed in a database;
  • dialogadddevice.h - header file dialog to add or edit entries;
  • dialogadddevice.cpp - source file dialog box to add and edit entries;
  • dialogadddevice.ui

Note. Most of the interface is created in the designer, so as not to clutter up the main logic code superfluous information. In fact it is only a matter of taste and habit.

mainwindow.ui

Form of the main window is simple. And you will use from this form the two objects:

  • addDeviceButton
  • deviceTableView

dialogadddevice.ui

In the form of the dialog box there are three fields a QLineEdit, two buttons and one ButtonBox, which is part of the default class that inherits from QDialog class.

We have the following items:

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

QDataMapperWidget.pro

The profile of the project need to add a directive that declares the use of libraries of 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

The file used in the project, being created by default.

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

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

    return a.exec();
}

mainwindow.h

The header of the main window define slots to start the dialogue add entries, update the model and start dialogue editing entries. There are also methods for initializing the appearance of the window, in addition to the basic settings made in Qt Designer interface, as well as the method of initialization data representation model.

#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

The source code of the main window initialization file data tables, as was done in a previous article, for example by working with QSqlTableModel . And also prescribes the logic behavior of the application by clicking the Add button, which causes the addition of recording the dialogue table. Also, this dialog is called by double-clicking on an entry in the data table. In this case, information transmitted in a dialogue on which recording has been pressed and its data are substituted into the field for editing.

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

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("QDataWidgetMapper Example");
    /* The first step is to create an object for the database 
     * and initialize the database connection
     * */
    db = new DataBase();
    db->connectToDataBase();

    /* Initialize the model to represent the data indicating the names of the columns
     * */
    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();
    /* Set the columns names in a table with sorted data
     * */
    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);     
    ui->deviceTableView->setColumnHidden(0, true); 
    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)));
}

/* Method for activating dialogue of adding records
 * */
void MainWindow::on_addDeviceButton_clicked()
{
    /* Create a dialogue and connect it to signal the completion 
     * of the form slot refresh data representation model
     * */
    DialogAddDevice *addDeviceDialog = new DialogAddDevice();
    connect(addDeviceDialog, SIGNAL(signalReady()), this, SLOT(slotUpdateModels()));

    addDeviceDialog->setWindowTitle(trUtf8("Добавить Устройство"));
    addDeviceDialog->exec();
}

/* Slot of update data representation model
 * */
void MainWindow::slotUpdateModels()
{
    modelDevice->select();
}

/* Method for activating dialogue adding entries to the edit mode 
 * with the transmission of the selected row index
 * */
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

Header File dialog for adding and editing entries. As can be seen on the header file, there is also used a model to represent the data, but it does not broadcast data to a QTableView , such as in the tutorial on QSqlRelationalModel or MainWindow class of this article, and in QDataWidgetMapper object class. There is also overridden by accept() method, as before, close the window, you must make sure that the data is filled in correctly. In this project, the criterion of correctness of filling of data is the lack of duplicates.

#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

In this file the logic of class was implemented. Checking the correctness of the entered data is carried out when you press the OK button. When properly filled fields produced record insert in the table and edit it. Validation of data in the IP адрес and MAC адрес is performed using a validator that writing has been described in a previous article . Also implemented on the verification record the existence of similar data.

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

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

    /* Method for initializing the model, from which data will be transmitted
     * */
    setupModel();

    /* If the string is not specified, that is equal to -1, 
     * then the dialog works on the principle of creating a new record. 
     * Namely, in the model of the new line is inserted and the work is done with it.
     * */
    if(row == -1){
        model->insertRow(model->rowCount(QModelIndex()));
        mapper->toLast();
    /* Otherwise, the dialogue is tuned to a given record
     * */
    } else {
        mapper->setCurrentModelIndex(model->index(row,0));
    }

    createUI();
}

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

void DialogAddDevice::setupModel()
{
    model = new QSqlTableModel(this);
    model->setTable(DEVICE);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();

    /* Initialize mapper and bind data fields to objects QLineEdit
     * */
    mapper = new QDataWidgetMapper();
    mapper->setModel(model);
    mapper->addMapping(ui->HostnameLineEdit, 1);
    mapper->addMapping(ui->IPAddressLineEdit, 2);
    mapper->addMapping(ui->MACLineEdit, 3);
    /* Manual confirmation of the change via the mapper
     * */
    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);

    /* Connect "Connects" from the scroll buttons to prilistyvaniyu data model mapper
     * */
    connect(ui->previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious()));
    connect(ui->nextButton, SIGNAL(clicked()), mapper, SLOT(toNext()));
    /* When you change the index mapper to change the state of the buttons
     * */
    connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(updateButtons(int)));
}

/* The method for installing the validator to enter the IP and MAC addresses
 * */
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-query to check for the existence of records with the same credentials. 
     * If a record does not exist or is only editable index is currently recording, 
     * the dialog box allows you to record in a data table
     * */
    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 a record exists, the dialog is a warning message
     * */
    if(query.value(0) != 0){
        QMessageBox::information(this, trUtf8("Ошибка хоста"),
                                 trUtf8("Хост с таким именем или IP-адресом уже существует"));
    /* Otherwise, you are inserting new data into the table and the dialogue ends 
     * with the transmission of a signal to update the table in the main window
     * */
    } else {
        mapper->submit();
        model->submitAll();
        emit signalReady();
        this->close();
    }
}

void DialogAddDevice::accept()
{

}

void DialogAddDevice::updateButtons(int row)
{
    /* In that case, if we reach one of the extremes (the first or the last) of the indices 
     * in the data table, then we change the state 
     * of a corresponding button on the inactive state
     * */
    ui->previousButton->setEnabled(row > 0);
    ui->nextButton->setEnabled(row < model->rowCount() - 1);
}

database.h

Helper class to work with the database is a modified variant of the same class from the previous lessons.

#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() << "Failed to restore the database";
        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()
{
    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)
{
    QSqlQuery query;
    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());

    if(!query.exec()){
        qDebug() << "error insert into " << DEVICE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    }
    return false;
}

Result

Archive with source: QDataWidgetMapper

The result it should look like as follows:

10% refund of hotel reservation amount on Booking
10% refund of hotel reservation amount on Booking
We offer a link with a 10% return on the amount of the order when booking a hotel through Booking
Support the author Donate

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

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? При редактировании записей никаких вопросов нет а вот при попытке добавления выдает ошибку.

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

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

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

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

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

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

t

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

QDialog dialog;
dialog.setModal(true);
dialog.show();
v

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

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

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

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

v

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

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

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

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

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

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

S

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

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

Добрый день!

Вспомогательный класс у меня кочевал из статьи к статье... Поэтому некоторые методы используются не во всех статьях.
Так получилось, что конкретно этот метод не используется в данном примере.
s
  • #
  • Feb. 16, 2018, 10:31 p.m.
  • , а можете подсказать пожалуйста, как выполнить поиск по какой то колонке и выбрать найденную запись?
QDataWidgetMapper работает на основе QSqlTableModel , следовательно вы можете пройтись в цикле по всем строкам модели данных и найти строку с нужными параметрами. Далее получается по номеру строки QModelIndex , который нужно передать в QDataWidgetMapper через метод setCurrentIndex . Тогда вы установить текущей записью нужную Вам строку.
k
  • #
  • March 22, 2018, 12:32 a.m.

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

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

Спасибо!

v

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

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

Добрый день!

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

@EVILEG can you kindly provide a response? Please

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.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
May 25, 2019, 4:20 p.m.
Андрей Янкович

C++ - Test 001. The first program and data types

  • Result:93points,
  • Rating points8
m
May 19, 2019, 1:49 a.m.
mahhaki

Qt - Test 001. Signals and slots

  • Result:78points,
  • Rating points2
S
May 17, 2019, 1:14 p.m.
SunBro

Qt - Test 001. Signals and slots

  • Result:42points,
  • Rating points-8
Last comments
May 21, 2019, 8:10 p.m.
Дмитрий

Приветствую! Я думаю дойдёт и до этого, но пока изучать его у меня нет желания.
May 20, 2019, 7:20 p.m.
Евгений Легоцкой

Добрый день! Вы не думали разместить репозиторий проекта на GitHub?
P.
May 18, 2019, 2:03 p.m.
PELMYACH .

Спасибо большое! Вскоре буду разбираться!
May 18, 2019, 9:13 a.m.
Евгений Легоцкой

Добрый день! Отнимать значение общего счётчика можно в деструкторе класса кнопки QDynamicButton::~QDynamicButton(){ ResID--;} При этом я бы ещё переустанавливал значения вс...
P.
May 14, 2019, 10:33 p.m.
PELMYACH .

Здравствуйте!А не подскажите, как можно при удалении какой либо кнопки, у щётчика отнять значение?Дабы например четвёртой кнопке соответствовал ID 4, а не 5 скажем
Now discuss on the forum
May 24, 2019, 6:48 a.m.
Евгений Легоцкой

Если там будут только перечисления внутри namespace, то жа, достаточно будет заголовочного файла
May 24, 2019, 6:28 a.m.
Андрей Янкович

работает любой http сервер, и можно использовать обсалютно любой портпример <RemoteRepositories> <Repository> <Url>http://178.124.160.6:3030/A/B&l...;
May 23, 2019, 2:40 p.m.
Михаиллл

Попробовал сделать этот запрос по http и получил json файл. request.setUrl(QUrl("https://jsonplaceholder.typicode.com/todos/1")); Как Вы думаете, почему https не работает и как это и...
May 23, 2019, 10:42 a.m.
Михаиллл

Спасибо, помогло.
May 23, 2019, 6:31 a.m.
Евгений Легоцкой

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

For registered users on the site there is a minimum amount of advertising

EVILEG
About
Services
Join us
© EVILEG 2015-2019
Recommend hosting TIMEWEB