За каждым клиентским приложением стоит система контроля и управления доступом. В этой статье описано создание приложения для авторизации и регистрации пользователей с использованием C++/Qt5. Создание приложения для авторизации состоит из 4 этапов:
подготовка файлов приложения;
разработка диалоговых окон;
реализация классов;
инициализация БД и интерфейса подключения к БД.
Приступим!
Этап №1: Подготовка файлов приложения
Начнем с создания нового проекта в Qt Creator. Для этого я воспользуюсь мастером создания новых проектов. В стартовом меню Qt Creator я выбираю "Новый проект" > "Приложение" > "Приложение QtWidgets"
:
Затем указываем имя, директорию и выбираем подходящий компилятор. В этом проекте уже будет заголовочный файл, форма и файл класса для главного окна MainWindow
. Для регистрации, хранения и извлечения пользовательской информации нам потребуется база данных (БД). Для этого подключаем модуль QtSql в конфигурации проекта — файле, имеющем имя проекта и расширение .pro:
Чтобы работать с классами этого модуля, нам нужно подключить заголовочный метафайл.
Классы модуля QtSql делятся на 3 уровня:
уровень драйверов — классы для получения данных на физическом уровне;
программный уровень — программный интерфейс для обращения к базе данных;
уровень пользовательского интерфейса — модели для отображения результатов запросов, представленные в форме вопросов-ответов.
Это приложение будет использовать классы второго уровня. Таким образом можно будет рассмотреть применение объектов класса QString для управления базой данных. Qt5 поддерживает следующие системы управления базами данных (СУБД):
Идентификатор | Описание |
QOCI | БД Oracle v7,8,9 |
QODBC | ODBC-сервер для Microsoft SQL Server, IBM DB2, Sybase SQL, iODBC и некоторых других |
QMYSQL | СУБД MySQL |
QTDS | Sybase Adaptive Server |
QPSQL | БД PostgreSQL с поддержкой SQL92/SQL3 |
QSQLITE | SQLite v2 |
QSQLITE | SQLite v3+ |
QIBASE | Borland InterBase |
QDB2 | DB2 от IBM |
Вы можете использовать идентификатор из этой таблицы для подключения к базе данных. Если вы не нашли здесь нужную СУБД, то вам придется самостоятельно написать для нее драйвер.
Наше приложение будет хранить свои данные локально, поэтому я воспользуюсь SQLite, так как драйвер этой СУБД и сама база по умолчанию всегда распространяются вместе с Qt5. Создаваемое приложение в своей работе будет оперировать тремя окнами:
MainWindow
— главное окно;
auth_window
— окно авторизации пользователя;
reg_window
— окно регистрации пользователя.
В проекте, созданном как "Приложение QtWidgets"
, по умолчанию создается окно MainWindow
, ассоциированное с классом MainWindow
.
Для реализации окон регистрации и авторизации добавим к проекту два новых класса формы QtDesigner. Для этого правой кнопкой мыши кликаем на папку проекта в «Обозревателе решений» и выбираем пункт "Добавить новый"
. Затем "Qt" > "Класс формы Qt Designer"
и нажимаем на кнопку "Выбрать"
:
Теперь в нашем проекте есть все нужные нам файлы и модуль для работы с базой данных:
Этап №2: Разработка диалоговых окон
Перед реализацией классов нам нужно разработать внешний вид диалоговых окон. Закончив этот этап, возвращаться к нему больше не придется.
Идея нашего приложения следующая: положение и размер главного окна запоминаются для каждого авторизованного пользователя. Авторизация и регистрация происходят в отдельных окнах, принадлежащих главному окну. Соединение с базой данных также принадлежит главному окну.
Начнем с разработки окна авторизации. Для этого откройте в редакторе файл auth_window.ui:
Для начала подбираем размеры окна, воспользовавшись синими маркерами по периметру. Затем размещаем слой позиционирования Layout
— просто перетаскиваем его из панели инструментов в наше окно. Для того, чтобы скомпоновать виджеты окна, как на вышеприведенном рисунке, нам нужно воспользоваться gridLayout
(впрочем, вы можете справиться и без него).
Далее нужно разместить виджеты окна: кнопки, поля, ярлыки. Перетаскивайте их с панели инструментов в слой позиционирования. Каждый новый виджет будет перераспределять положение всех виджетов слоя. Как вы можете видеть, в этом окне используются виджеты QLabel, QLineEdit и QPushButton (не считая QGridLayout). Закончив размещать виджеты в окне, воспользуйтесь инструментом изменения порядка обхода (при использовании табуляции), кнопка для включения этого инструмента находится на панели сразу над областью редактирования:
Рекомендую называть виджеты в соответствии с их предназначением. Например, название loginPushButton
явно говорит нам о назначении этого объекта, в отличие от lineEdit_2
.
Вы можете изменить атрибуты виджетов, например, можно разместить надписи виджетов Qlabel по правому краю, изменив свойство QLabel.alignment
:
Последний этап проектирования окна — это объявление слотов. Для этого вызовите контекстное меню виджета и выберите пункт "Перейти к слоту"
. В появившемся окне выбираем слот textEdited(QString)
виджета QLineEdit
:
Также нам потребуется слот clicked()
виджета QAbstractButton
:
Прототипы слотов будут созданы в заголовочном файле, а их реализация появится в файле auth_window.cpp. Разработка внешнего вида окна авторизации завершена.
Перейдем к разработке внешнего вида окна регистрации, для этого откройте файл reg_window.ui:
Повторите шаги, сделанные для предыдущего окна: подберите размер окна, разместите слой позиционирования, разместите виджеты в слое, дайте корректные имена созданным виджетам и создайте слоты textEdited(QString)
для полей и clicked()
для кнопки. Не забудьте расставить порядок перехода между виджетами при использовании табуляции.
Этап №3: Реализация классов
Все файлы и необходимые им слоты созданы, теперь можно приступить к описанию классов. Начинать реализацию классов лучше с объявления членов класса в заголовочном файле. Для реализации класса MainWindow
понадобится подключить следующие заголовочные файлы:
QMainWindow;
QString;
QtSql.
В файле mainwindow.h подключаем необходимые библиотеки и заголовочные файлы, а также необходимо подключить заголовочные файлы окон регистрации и авторизации:
1 2 3 4 5 |
#include <QMainWindow> #include <QString> #include <QtSql/QtSql> #include "auth_window.h" #include "reg_window.h" |
Хотя Qt Creator поместил MainWindow
по умолчанию в пространство имен Ui
:
1 2 3 |
namespace Ui { class MainWindow; } |
Не все функции класса будут сосредоточены на пользовательском интерфейсе. Так как я намерен вызывать главное окно лишь после успешной авторизации, мне понадобится создать public-метод display() для отображения главного окна. Для работы с базой данных мне понадобится public-метод connectDB(), а также экземпляр подключения к БД — mw_db
, и строка для формирования запроса к БД — db_input
.
Использование прочих членов класса MainWindow
можно проследить в файле класса MainWindow.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); void display(); // прототип пользовательской функции отображения bool connectDB(); // прототип метода подключения к БД private: Ui::MainWindow *ui_Main; auth_window ui_Auth; // экземпляры окна авторизации и окна регистрации reg_window ui_Reg; // принадлежат главному окну QString m_username; // строки для обработки QString m_userpass; // пользовательского ввода QString db_input; // строка для отправки запроса к БД QSqlDatabase mw_db; // экземпляр подключения к БД int user_counter; // счетчик пользователей bool m_loginSuccesfull; // флаг успешной авторизации private slots: void authorizeUser(); // пользовательские слоты void registerWindowShow(); void registerUser(); }; |
Файл auth_window.h
Кроме автоматически созданных членов и слотов, классу окна авторизации понадобятся сигналы, которые окно авторизации будет посылать главному окну. Также понадобится пара переменных для хранения пользовательского ввода и геттеры для их получения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <QWidget> namespace Ui { class auth_window; } class auth_window : public QWidget { Q_OBJECT public: explicit auth_window(QWidget *parent = nullptr); ~auth_window(); QString getLogin(); QString getPass(); signals: void login_button_clicked(); void register_button_clicked(); private slots: void on_lineEdit_textEdited(const QString &arg1); void on_lineEdit_2_textEdited(const QString &arg1); void on_loginPushButton_clicked(); void on_registerPushButton_2_clicked(); private: Ui::auth_window *ui; QString m_username; QString m_userpass; }; |
Файл reg_window.h
Окну регистрации понадобится сигнал, который оно будет посылать главному окну, переменные для хранения пользовательского ввода и геттеры для них, а также я решил добавить функцию проверки пользователя на внимательность:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <QWidget> namespace Ui { class reg_window; } class reg_window : public QWidget { Q_OBJECT public: explicit reg_window(QWidget *parent = nullptr); ~reg_window(); QString getName(); QString getPass(); bool checkPass(); signals: void register_button_clicked2(); private slots: void on_nameLineEdit_textEdited(const QString &arg1); void on_passwordLineEdit_textEdited(const QString &arg1); void on_confirmLineEdit_textEdited(const QString &arg1); void on_registerPushButton_clicked(); private: Ui::reg_window *ui; QString m_userName; QString m_userPass; QString m_confirmation; }; |
Файл auth_window.cpp
В автоматически созданных файлах класса содержимое конструкторов создается по умолчанию. В этом классе меня это устраивает:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "auth_window.h" #include "ui_auth_window.h" auth_window::auth_window(QWidget *parent) : QWidget(parent), ui(new Ui::auth_window) { ui->setupUi(this); } auth_window::~auth_window() { delete ui; } |
В автоматически созданных слотах кнопок размещаю сигналы, объявленные в заголовочном файле:
1 2 3 4 5 6 7 8 9 |
void auth_window::on_registerPushButton_2_clicked() { emit register_button_clicked(); } void auth_window::on_loginPushButton_clicked() { emit login_button_clicked(); } |
В автоматически созданных слотах полей копирую содержимое полей в переменные класса:
1 2 3 4 5 6 7 8 9 |
void auth_window::on_lineEdit_textEdited(const QString &arg1) { auth_window::m_username = arg1; } void auth_window::on_lineEdit_2_textEdited(const QString &arg1) { auth_window::m_userpass = arg1; } |
Таким образом геттеры возвращают содержимое полей:
1 2 3 4 5 6 7 8 9 |
QString auth_window::getLogin() { return auth_window::m_username; } QString auth_window::getPass() { return auth_window::m_userpass; } |
Файл reg_window.cpp
Конструктор и деструктор по умолчанию:
1 2 3 4 5 6 7 8 9 10 11 |
reg_window::reg_window(QWidget *parent) : QWidget(parent), ui(new Ui::reg_window) { ui->setupUi(this); } reg_window::~reg_window() { delete ui; } |
Слот кнопки регистрации вызывает сигнал для главного окна:
1 2 3 4 |
void reg_window::on_registerPushButton_clicked() { emit register_button_clicked2(); } |
Слоты полей копируют пользовательский ввод:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void reg_window::on_nameLineEdit_textEdited(const QString &arg1) { reg_window::m_userName = arg1; } void reg_window::on_passwordLineEdit_textEdited(const QString &arg1) { reg_window::m_userPass = arg1; } void reg_window::on_confirmLineEdit_textEdited(const QString &arg1) { reg_window::m_confirmation = arg1; } |
Геттеры возвращают пользовательский ввод:
1 2 3 4 5 6 7 8 9 |
QString reg_window::getName() { return m_userName; } QString reg_window::getPass() { return m_userPass; } |
Функция checkPass() возвращает true
, если пользователь не ошибся при подтверждении пароля в поле confirm
:
1 2 3 4 |
bool reg_window::checkPass() { return (m_confirmation == m_userPass); } |
Этап №4: Инициализация БД и интерфейса подключения к БД
На этом этапе мы работаем с файлом main_window.cpp. Первым делом нам нужно подключить файлы других классов с помощью директивы #include
:
1 2 3 4 5 |
#include "mainwindow.h" #include "ui_mainwindow.h" #include "auth_window.h" #include "reg_window.h" #include <QtDebug> |
Модуль QtDebug
используется для отображения ошибок программы в окне Qt Creator, вместо отображения в консоли или в виджете.
В конструкторе главного окна можно соединить сигналы со слотами и осуществить соединение с БД, а также создать в ней новую таблицу. Библиотека QtSql
обеспечивает нам доступ к сообщениям с ошибками, которые формируются запросами QSqlQuery
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui_Main(new Ui::MainWindow) { user_counter = 0; m_loginSuccesfull = false; connect(&ui_Auth, SIGNAL(login_button_clicked()), this, SLOT(authorizeUser())); connect(&ui_Auth,SIGNAL(destroyed()), this, SLOT(show())); connect(&ui_Auth,SIGNAL(register_button_clicked()), this,SLOT(registerWindowShow())); connect(&ui_Reg,SIGNAL(register_button_clicked2()), this,SLOT(registerUser())); connect(&ui_Reg,SIGNAL(destroyed()), &ui_Auth, SLOT(show())); if(!connectDB()) { qDebug() << "Failed to connect DB"; } QSqlQuery query; db_input = "CREATE TABLE userlist ( " "number INTEGER PRIMARY KEY NOT NULL," "name VARCHAR(20), " "pass VARCHAR(12), " "xpos INTEGER, " "ypos INTEGER, " "width INTEGER, " "length INTEGER );"; if(!query.exec(db_input)) { qDebug() << "Unable to create a table" << query.lastError(); } ui_Main->setupUi(this); } |
Функция authorizeUser() соединена с сигналом кнопки авторизации. Она сохраняет пользовательский ввод, составляет из него запрос к БД, проверяет хранимый пароль на соответствие тому, который ввел пользователь и, в случае успеха, открывает MainWindow
с параметрами, сохраненными из предыдущей сессии:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
void MainWindow::authorizeUser() { m_username = ui_Auth.getLogin(); m_userpass = ui_Auth.getPass(); QString str_t = " SELECT * " " FROM userlist " " WHERE name = '%1'"; // int db_number = 0; QString username = ""; QString userpass = ""; int xPos = 0; int yPos = 0; int width = 0; int length = 0; db_input = str_t.arg(m_username); QSqlQuery query; QSqlRecord rec; if(!query.exec(db_input)) { qDebug() << "Unable to execute query - exiting" << query.lastError() << " : " << query.lastQuery(); } rec = query.record(); query.next(); user_counter = query.value(rec.indexOf("number")).toInt(); username = query.value(rec.indexOf("name")).toString(); userpass = query.value(rec.indexOf("pass")).toString(); if(m_username != username || m_userpass != userpass) { qDebug() << "Password missmatch" << username << " " << userpass; m_loginSuccesfull = false; } else { m_loginSuccesfull = true; xPos = query.value(rec.indexOf("xpos")).toInt(); yPos = query.value(rec.indexOf("ypos")).toInt(); width = query.value(rec.indexOf("width")).toInt(); length = query.value(rec.indexOf("length")).toInt(); ui_Auth.close(); ui_Reg.close(); this->setGeometry(xPos,yPos,width, length); this->show(); } } |
Функция registerWindowShow() соединена с сигналом register_button_clicked()
. Она скрывает окно авторизации и вызывает окно регистрации:
1 2 3 4 5 |
void MainWindow::registerWindowShow() { ui_Auth.hide(); ui_Reg.show(); } |
Функция registerUser() соединена с сигналом кнопки регистрации, расположенной в окне регистрации. Она выполняет проверку пользовательского ввода, получает новый номер записи из БД и регистрирует пользователя. Вы могли заметить, что у поля name
при создании новой БД не было идентификатора unique
, остальная часть программы тоже не выполняет проверки на уникальность регистрируемого имени:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
void MainWindow::registerUser() { if(ui_Reg.checkPass()) { QSqlQuery query; QSqlRecord rec; QString str_t = "SELECT COUNT(*) " "FROM userlist;"; db_input = str_t; if(!query.exec(db_input)) { qDebug() << "Unable to get number " << query.lastError() << " : " << query.lastQuery(); return; } else { query.next(); rec = query.record(); user_counter = rec.value(0).toInt(); qDebug() << user_counter; } m_username = ui_Reg.getName(); m_userpass = ui_Reg.getPass(); user_counter++; str_t = "INSERT INTO userlist(number, name, pass, xpos, ypos, width, length)" "VALUES(%1, '%2', '%3', %4, %5, %6, %7);"; db_input = str_t .arg(user_counter) .arg(m_username) .arg(m_userpass) .arg(0) .arg(0) .arg(800) .arg(400); if(!query.exec(db_input)) { qDebug() << "Unable to insert data" << query.lastError() << " : " << query.lastQuery(); } else { ui_Reg.hide(); ui_Auth.show(); } } else { qDebug() << "Confirm password coorectly"; } } |
Метод display() подменяет вызов главного окна вызовом окна авторизации:
1 2 3 4 |
void MainWindow::display() { ui_Auth.show(); } |
Деструктор главного окна, в случае удачной авторизации, обновляет содержимое записи в БД и прерывает соединение с БД, а затем уничтожает окна приложения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
MainWindow::~MainWindow() { if(m_loginSuccesfull) { QString str_t = "UPDATE userlist " "SET xpos = %2, ypos = %3, width = %4, length = %5 " "WHERE name = '%1';"; db_input = str_t .arg(m_username) .arg(this->x()) .arg(this->y()) .arg(this->width()) .arg(this->height()); QSqlQuery query; if(!query.exec(db_input)) { qDebug() << "Unable to insert data" << query.lastError() << " : " << query.lastQuery() ; } } mw_db.removeDatabase("authorisation"); qDebug() << "MainWindow Destroyed"; delete ui_Main; exit(0); } |
Функция connectDB() устанавливает имя БД и создает соединение с ней. После того, как эта функция будет выполнена впервые, в директории программы появится файл с именем, указанным здесь для базы данных:
1 2 3 4 5 6 7 8 9 10 11 |
bool MainWindow::connectDB() { mw_db = QSqlDatabase::addDatabase("QSQLITE"); mw_db.setDatabaseName("authorisation"); if(!mw_db.open()) { qDebug() << "Cannot open database: " << mw_db.lastError(); return false; } return true; } |
Конечный результат работы нашего приложения авторизации/регистрации, написанного с помощью C++/Qt5:
Заключение
Теперь, если вы решите написать приложение, требующее авторизации пользователей, у вас есть пример того, как это можно сделать. В вашем приложении параметрами авторизации могут быть: голос, отпечатки пальцев, фото пользователя или что-то другое. Вы наверняка будете передавать пользовательский ввод для авторизации на удаленный сервер, обеспечите уникальность каждого имени и зашифруете канал связи. Уверен, что у вас всё получится!
Исходный код форм регистрации и авторизации на C++/Qt5.
Здраствуйте! Помогите пожалуйста. Когда я в окне регистрации регистрирую пользователя, он не попадает в базу данных и когда я в окне авторизации ввожу зарегестрированого пользователя то мне в консоле пишет:
Password missmatch "" "".
А сразу при запуске программы пишет:
qt.core.qmetaobject.connectslotsbyname: QMetaObject::connectSlotsByName: No matching signal for on_LineEdit_testEdited(QString)
qt.core.qmetaobject.connectslotsbyname: QMetaObject::connectSlotsByName: No matching signal for on_nameLineEdit_textEdited(QString)
qt.core.qmetaobject.connectslotsbyname: QMetaObject::connectSlotsByName: No matching signal for on_passwordLineEdit_textEdited(QString)
qt.core.qmetaobject.connectslotsbyname: QMetaObject::connectSlotsByName: No matching signal for on_confirmLineEdit_textEdited(QString)
Unable to create a table QSqlError("1", "Unable to execute statement", "table userlist already exists")
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
Как мне решить эту проблему? Буду очень благодарен за помощь.
Лучшим советом будет использование вывода сообщений в дебаггер на каждом этапе работы программы. Это самый легкий путь поиска ошибок.
Так же изучите SQL запросы, чтобы были уверены что все делаете правильно. Вам в консоль пишет что вы создаете таблицу с уже существующим именем повторно. А так же ругается на сигналы QLineEdit
Спасибо!
Здраствуйте! У меня при нажатии кнопки регистрации окно регистрации не запускается а просто в концоле пишется user_counter(цифры).
Как мне это исправить?
Для выполнения этого урока пришлось сперва выучить SQLite запросы, а затем вернуться 😉
Реализовал все по-своему, в MSVS2022 Enterprise Edition + Qt6. Загрузить код сюда в удобной форме, чтобы он был вам полезен, уже не выйдет, поэтому вот ссылка на мой проект на GitHub — Finchi’s project
Все особенности реализации будут понятны из комментариев к коду.
А тут напишу об особенностях построения проекта в Visual Studio:
В отличии от Qt Creator файла проекта с расширением .pro у нас нет, поэтому базу данных нужно подключить еще на этапе создания проекта, кроме стандартных для Qt Widget Application модулей (Qt Core, Qt GUI, Qt Widgets) нужно подключить модуль Qt SQL
Если проект уже создан, а модуль Qt SQL включить в него забыли, то можно это сделать кликнув правой клавишей по проекту в Обозревателе решений -> Свойства -> Qt Project Settings -> Qt Modules -> <Sellect Modules…> и тут выбрать Qt SQL
Это, пожалуй, единственное в чем нужно разобраться, чтобы сделать аналогичный проект в Visual Studio
Чтобы при запуске программы открывалось окно для ввода данных, нужно в main.cpp вместо
написать
Вдогонку к своему комментарию от 23.12: в папке release проекта создать папку sqldrivers и поместить туда файл qsqlite.dll из папки C:\Qt\Qt5.10.1\5.10.1\mingw53_32\plugins\sqldrivers. Платформа windows7x64.
Здравствуйте! Проект компилируется, но тут же вылетает с ошибками:
QSqlDatabase: QSQLITE driver not loaded
QSqlDatabase: available drivers:
Cannot open database: QSqlError("", "Driver not loaded", "Driver not loaded")
Failed to connect DB
QSqlQuery::exec: database not open
Unable to create a table QSqlError("", "Driver not loaded", "Driver not loaded")
QSqlDatabase: QSQLITE driver not loaded
QSqlDatabase: available drivers:
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
Cannot open database: QSqlError("", "Driver not loaded", "Driver not loaded")
Всё работает! Большое Человеческое спасибо!
Для тех, у кого сначала запускается окно MainWindow до формы регистрации — необходимо в main убрать строку, вызывающую метод show() объекта MainWindow.
Плюс создал объекты ui_Reg и ui_Auth в куче, ui_Auth->show() в конструкторе, все работает правильно.
Большое спасибо автору за урок!
Здравствуйте. Подскажите как расставляется порядок появления окон? Если скопипастить весь код, выходит так что сначала открывается главная форма, а потом регистрация и вход.
здравствуйте, сделал все по вашему алгоритму. При попытке запустить программу выдало много ошибок по типу "отсутствует QCored.dll(Qwidgetsd.dll)"и тд. Исправил путем копирования этих файлов из Qt папки в папку с программой, но теперь при запуске я вижу пустое окно mainwindow — больше ничего не происходит. Помогите пожалуйста
здравствуйте, помогите разобраться, туплю, скопировал в один в один ваш проект попробовал с sqllite, все работает, но мне нужно что нибудь подобное на psql, и только я меняю значение addDatabase(QPSQL), приложение компилируется, запускается и сразу же вылетает, вот что пишет:
QMetaObject::connectSlotsByName: No matching signal for on_lineEdit_textEdited(QString)
Cannot open database: QSqlError("", "QPSQL: Unable to connect", "fe_sendauth: no password supplied\n")
Failed to connect DB
QSqlQuery::exec: database not open
Unable to create a table QSqlError("", "", "")
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
Cannot open database: QSqlError("", "QPSQL: Unable to connect", "fe_sendauth: no password supplied\n")
Добрый день. В исходниках не оказалось mainwindow.ui файла.
Не знаю задумано так или забыли.
Спасибо за статью, очень полезная информация!
Добрый день.
Файл mainwindow.ui создаётся автоматически, если следовать этой инструкции. Он не содержит ничего, кроме автоматически созданной формы. До сих пор не было смысла его приводить.