D
April 20, 2017, 3:29 a.m.

Ошибка соединения

Здравствуйте. Делаю программу, в которой идет сначала авторизация в БД по логин/паролю, после чего, относительно того какая роль, открывает определенно окно, после открытия окна(для Администратора) производится запись в TableView. Если писать соединение сразу в main.cpp, то все прекрасно отображает,но у меня идет соединение через форму enterform. Если произвожу авторизацию через нее, то возникает такое окошко(Driver not loaded) и соответственно выборка не производится, но открывает нужное окно, где есть кнопка "Найти", после нажатия на которую, производится выборка. Я так понимаю, авторизация происходит как бы позже. Тогда возникает такой вопрос? Как это сделать правильно? Думал использовать QDialog,но как возвратит строку обратно в main.cpp? Или возможно ли не использовать QMainWindow(если допустим не нужны меню и прочее?) или он обязателен?

enterform::enterform(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::enterform)
{
    ui->setupUi(this);
    //AdminForm = new AdministrationForm();
    QSettings settings("SOK", "Connection");
    ui->savecheckbox->setChecked(settings.value("saveSetting", false).toBool());
    if (ui->savecheckbox->isChecked())
    {
        QString user=settings.value("user").toString();
        QString pass=settings.value("pass").toString();
        ui->login->setText(user);
        ui->password->setText(pass);
    }
}

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

void enterform::on_EnterButton_clicked(){
    
    AdminForm = new AdministrationForm();
    QSettings settings("SOK", "Connection");
    QString host=settings.value("host").toString();
    int port=settings.value("port").toInt();
    QString base=settings.value("base").toString();
    QSqlDatabase db=QSqlDatabase::addDatabase("QPSQL");

    db.setHostName(host);
    db.setPort(port);
    db.setDatabaseName(base);
    db.setUserName(ui->login->text());
    db.setPassword(ui->password->text());


    if (db.open())
    {
        QSqlQuery query;
        if (ui->savecheckbox->isChecked()){

            settings.setValue("saveSetting", true);
            settings.setValue("user", ui->login->text());
            settings.setValue("pass",ui->password->text());

            query.exec("SELECT r.rolname FROM pg_catalog.pg_auth_members m, pg_catalog.pg_roles r WHERE m.roleid=r.oid and m.member =(SELECT oid FROM pg_catalog.pg_roles WHERE rolname = '"+ui->login->text()+"');");
            while (query.next())
            {
                QString rolname = query.value(0).toString();
                if (rolname == "Administation")
                   {
                    this->close();
                    AdminForm->showMaximized();

                   }
                else if(rolname == "director")
                    {
                    qDebug() << "test";
                    }
             }
        }
        else
        {
          settings.setValue("saveSetting", false);
          settings.setValue("user", ui->login->text());
          this->close();
        }
    }
    else
    {
        QMessageBox::warning(0, QObject::tr("Error"), db.lastError().databaseText());
    }


}
#include "administrationform.h"
#include "ui_administrationform.h"
#include <QTableView>
#include <QSqlError>
#include <QMessageBox>

AdministrationForm::AdministrationForm(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::AdministrationForm)
{
    ui->setupUi(this);
    AllClientSelect();
}

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

void AdministrationForm::AllClientSelect()
{
    allClienttable = new QSqlQueryModel(this);
    allClienttable->setQuery("SELECT nomer_abonementa,familiya,imya,otchestvo,end_ref,mobile FROM klient");
      if (allClienttable->lastError().isValid())
      {
          QMessageBox::information(this, tr("TestErr"), allClienttable->lastError().databaseText());
      }
    allClienttable->setHeaderData(0, Qt::Horizontal, tr("Номер Абонемента"));
    allClienttable->setHeaderData(1, Qt::Horizontal, tr("Фамилия"));
    allClienttable->setHeaderData(2, Qt::Horizontal, tr("Имя"));
    allClienttable->setHeaderData(3, Qt::Horizontal, tr("Отчество"));
    allClienttable->setHeaderData(4, Qt::Horizontal, tr("Конец справки"));
    allClienttable->setHeaderData(5, Qt::Horizontal, tr("Телефон"));

    ui->allClient->setModel(allClienttable);
    ui->allClient->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->allClient->setColumnHidden(0, true);
    ui->allClient->setEditTriggers(QAbstractItemView::NoEditTriggers);
}

void AdministrationForm::on_pushButton_5_clicked()
{
        allClienttable = new QSqlQueryModel(this);
        allClienttable->setQuery("SELECT nomer_abonementa,familiya,imya,otchestvo,end_ref,mobile FROM klient");

        allClienttable->setHeaderData(0, Qt::Horizontal, tr("Номер Абонемента"));
        allClienttable->setHeaderData(1, Qt::Horizontal, tr("Фамилия"));
        allClienttable->setHeaderData(2, Qt::Horizontal, tr("Имя"));
        allClienttable->setHeaderData(3, Qt::Horizontal, tr("Отчество"));
        allClienttable->setHeaderData(4, Qt::Horizontal, tr("Конец справки"));
        allClienttable->setHeaderData(5, Qt::Horizontal, tr("Телефон"));
        ui->allClient->setModel(allClienttable);
        //Разрешаем выделение строк
        ui->allClient->setSelectionBehavior(QAbstractItemView::SelectRows);
        ui->allClient->resizeColumnsToContents();
        ui->allClient->setEditTriggers(QAbstractItemView::NoEditTriggers);

}
2

Do you like it? Share on social networks!

3
Evgenii Legotckoi
  • April 20, 2017, 12:37 p.m.

У вас путаница с последовательностью действий. Нужно сделать авторизацию. И передать дальше управление в другое окно. Но при этом сам объект базы данных существует локально в методе on_EnterButton_clicked() . db сохраняется в стеке и не существует в другом окне, скорее всего соединение падает при окончании работы метода on_EnterButton_clicked() . Лучше делать обёртку, для работы с подключением к базе данных. Создать объект этой обертки к базе данных и через метод подключения передать по сигналам данные для авторизации. Также стоит выделить память через new для этого объекта обёртки. Класс обёртки у меня есть в следующей статье . Там есть метод connectToDataBase() , можете его переделать, чтобы он принимал в качестве аргументов пароль, логин и т.д. А возвращал например роль. Что касается передачи информации между окнами, то можете посмотреть вот этот пример . Там окна взаимодействуют через сигналы и слоты, как раз то, что нужно, чтобы вернуть данные из кона авторизации в главное окно.

Что касается использования QMainWindow, то можно использовать в качестве окна даже простой QWidget, но QDialog имеет уже встроенные стандартные кнопки.

Вообще, сам вот этот код должен быть в неком ядре программы, а не в конкретном окне.

QSqlDatabase db=QSqlDatabase::addDatabase("QPSQL");

db.setHostName(host);
db.setPort(port);
db.setDatabaseName(base);
db.setUserName(ui->login->text());
db.setPassword(ui->password->text());

db.open()

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

    D
    • April 21, 2017, 12:52 a.m.

    Я нашел ошибку у себя, у меня получалось, что я создавал объект main окно до соединения с БД, из-за этого писало ошибку, переместил строку AdminForm = new AdministrationForm(); и все заработало, но перед этим сделал как вы просили, сделал отдельный класс для соединения с бд,в которую передавал значения и принимал. Я так понимаю верным должен быть 2 вариант, но почему? Разве объект БД не будет существовать до окончания программы?

      Evgenii Legotckoi
      • April 21, 2017, 9:45 a.m.
      • The answer was marked as a solution.

      Когда вы вызываете данный метод:

      QSqlDatabase db=QSqlDatabase::addDatabase("QPSQL");

      Вы сохраняете объект базы данных в стеке, то есть объект существует локально внутри метода on_EnterButton_clicked . А что происходит со всеми локальными переменными, когда метод заканчивает свою работу? Правильно, они уничтожаются. А вместе с этим уничтожением закрывается соединение с базой данных. Почему оно закрывается? Потому что локальный объект уничтожен и память освобождена. Хорошо, что ещё Segmentation Fault не словили.

      Конечно, в случае с QSqlDataBase всё обстоит хитрее, там несколько сложнее всё сделано внутри, поскольку сохраняются имена соединений, но, как я считаю, работать базаданных будет до тех пор, пока под неё выделена память. В конце концов QSqlDataBase хранит логин, пароль, порт, IP и т.д, а если память была освобождена, то куда это всё будет помещено? Никуда, пропадёт. Поэтому лучше держать базу данных за фассадом-обёрткой, чтобы всегда была выделена память под объект базы данных. В моём варианте с обёрткой, память выделенная под базу данных существует до конца работы программы.

        Comments

        Only authorized users can post comments.
        Please, Log in or Sign up
        • Last comments
        • AK
          April 1, 2025, 11:41 a.m.
          Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
        • Evgenii Legotckoi
          March 9, 2025, 9:02 p.m.
          К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
        • VP
          March 9, 2025, 4:14 p.m.
          Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
        • ИМ
          Nov. 22, 2024, 9:51 p.m.
          Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
        • Evgenii Legotckoi
          Oct. 31, 2024, 11:37 p.m.
          Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup