Russian Qt Forum
Сентябрь 30, 2024, 10:35 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Нубский вопрос по глобальным переменным  (Прочитано 4857 раз)
Zebar
Гость
« : Июль 21, 2010, 22:57 »

Народ, ногами не пинайте - C/C++ учил 14 лет назад  еще в институте. Сейчас решил для себя повспоминать, попробовать освоить Qt. Но в 3 соснах заблудился.

Вопрос:
Для программы нужно постоянное обращение к базе данных SQLite. Чтобы его каждый раз не создавать - хочу при запуске программы проинициализировать, открыть базу, при необходимости - создать ее со всей структурой, заполнить данными по умолчанию и т.д. А дальше - чтобы все остальные могли к базе обращаться и делать нужные действия. Для этого создал класс со своими методами:
Код:
#ifndef SQLDATA_H
#define SQLDATA_H

#include <QObject>
#include "QtSql/QSqlDatabase"
#include "QtSql/QSqlQuery"

class SqlData : public QObject
{
    Q_OBJECT
public:
    QSqlQuery query;
    void Init(void);
    explicit SqlData(QObject *parent = 0);
    QSqlDatabase db;


signals:

public slots:

private:

};

#endif // SQLDATA_H

Как я понимаю, мне нужно объявить глобальную переменную типа класса в одном cpp модуле, а в других - указать, что эта переменная - extern.
Но что-то у меня ни фига не выходит.
В модуле sqldata.cpp пишу
Код:
SqlData DataBase;
В остальных пишу
Код:
extern SqlData DataBase;
Написалфункцию Init, которая вызывается и заполняет таблицу данными - тут все хорошо. Внутри функции main
Код:
    DataBase.Init();
Судя по логам - все хорошо.
А вот в модуле другого окна пишу:
Код:
extern SqlData DataBase;

BreedDialog::BreedDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::BreedDialog)
{
    ui->setupUi(this);
    ui->BreedSelectComboBox->insertItem(0,"<New breed...>");
    ui->BreedSelectComboBox->insertSeparator(0);
    DataBase.query.exec("select * from breeds;");
    qDebug() << DataBase.db.isOpen();
    while (DataBase.query.next()) {
        QString name = DataBase.query.value(1).toString();
        qDebug() << name;
    }
}


Мне в логи мусорит QSqlQuery::exec: database not open
Причем, по логам же, после инициализации.
Где я напортачил?

Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Июль 22, 2010, 03:20 »

в статик переменной. Для коннекта к БД (насколько я знаю) используются плагины, которые еще не загружены на момент инициализации глобальной переменной (тк QApplication еще не создан)
Да, и при объявлении статик переменных extern не надо
Записан
Zebar
Гость
« Ответ #2 : Июль 22, 2010, 09:31 »

в статик переменной. <...> Да, и при объявлении статик переменных extern не надо
То есть вместо extern написать static?
Для коннекта к БД (насколько я знаю) используются плагины, которые еще не загружены на момент инициализации глобальной переменной (тк QApplication еще не создан)
Нет, это не то. Смотрю через qDebug - сначала выполняется функция Init(), которая успешно отрабатывает, а затем уже в конструкторе BreedDialog выполняется запрос к уже открытой базе, на который я получаю ответ, что база не открыта.
Может быть, я первоначально неправильно делаю? Какова типовая практика для таких случаев?
Записан
crossly
Гость
« Ответ #3 : Июль 22, 2010, 09:54 »

возможно вы не весь код показали... но я не вижу где же собственно происходит открытие БД... ??
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Июль 22, 2010, 16:56 »

Да вроде все Вы правильно делаете. Попробуйте обратиться к базе после Init в том же файле, может extern здесь ни при чем
Записан
BRE
Гость
« Ответ #5 : Июль 22, 2010, 17:21 »

Совсем все не правильно.
На момент создания объекта query, база данных должна быть уже открыта, т.к. используется конструктор:
QSqlQuery::QSqlQuery ( const QString & query = QString(), QSqlDatabase db = QSqlDatabase() )
в котором используется соединение с БД по умолчанию.

Класс QSqlDatabase специально создан таким образом, что бы в любом месте программы можно было получить соединение с БД.
Код
C++ (Qt)
void Class::InitDatabase()
{
QSqlDatabase db1 = QSqlDatabase::addDatabase( "QSQLITE" ); // Добавили подключение с именем по умолчанию
QSqlDatabase db2 = QSqlDatabase::addDatabase( "QSQLITE", "SpecialConnect" ); // Добавили подключение с именем SpecialConnect
...
if( !db1.open() || !db2.open() )
// error
}
 
void Class::method1()
{
QSqlDatabase db2 = QSqlDatabase::database( "SpecialConnect" ); // Получили соединение с именем SpecialConnect
QSqlQuery query1( db2 ); // Использует подключение с именем SpecialConnect
}
 
void Class::method2()
{
QSqlDatabase db1 = QSqlDatabase::database(); // Получили соединение с именем по умолчанию
QSqlQuery query1( db1 ); // Использует подключение с именем по умолчанию
// или просто
QSqlQuery query2(); // Использует подключение с именем по умолчанию
}
 

Поэтому, нет необходимости (и даже вредно) делать запросы и подключения глобальными. Вредно потому, что в дальнейшем будет не возможно удалить соединение, т.к. будет постоянно существовать объект класса QSqlQuery, который им пользуется.
Записан
Zebar
Гость
« Ответ #6 : Июль 22, 2010, 21:09 »

Цитировать
Совсем все не правильно.
На момент создания объекта query, база данных должна быть уже открыта, т.к. используется конструктор:
QSqlQuery::QSqlQuery ( const QString & query = QString(), QSqlDatabase db = QSqlDatabase() )
в котором используется соединение с БД по умолчанию.
в общем, это все так и все понятно.
Просто у меня есть
QApplication a
MainWindow w;
И есть еще класс BreedDialog
и я
1. Никак не соображу, где и когда создается объект класса BreedDialog (то есть еще окошко)
2. Во всех этих разных классах, да и еще в десятко еще не созданных форм, придется создавать запросы к базе. Поэтому, как я понимаю, так как у них нет ничего, общего, надо все-таки создать QSqlQuery, чтобы все им пользовались.
Записан
Zebar
Гость
« Ответ #7 : Июль 22, 2010, 21:19 »

Мне кажется, я разобрался.
Надо в любом месте создать QSqlDatabase по умолчанию и открыть его
А потом из любого места QSqlQuery будет обращаться именно к нему.
Записан
BRE
Гость
« Ответ #8 : Июль 22, 2010, 21:26 »

Мне кажется, я разобрался.
Надо в любом месте создать QSqlDatabase по умолчанию и открыть его
А потом из любого места QSqlQuery будет обращаться именно к нему.

Не обязательно получать соединение по умолчанию с помощью метода QSqlDatabase::database, можно просто создавать объект QSqlQuery в нужном месте не указывая параметр db, тогда будет автоматически использоваться соединение по умолчанию. Главное, что бы это соединение уже было создано и база открыта.

« Последнее редактирование: Июль 22, 2010, 21:42 от BRE » Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #9 : Июль 22, 2010, 21:26 »

Надо в любом месте создать QSqlDatabase по умолчанию и открыть его
А потом из любого места QSqlQuery будет обращаться именно к нему.
совершенно верно
Записан

Юра.
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.076 секунд. Запросов: 23.