Russian Qt Forum

Qt => Базы данных => Тема начата: chester от Ноябрь 11, 2011, 09:16



Название: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 11, 2011, 09:16
Приветствую всех!!!
Я только начинаю работать с БД. Отображаю содержимое таблиц с помощью с помощью QTableModel -> QTableView. На одной форме у меня отображаются сразу 3 таблицы с данными. И при этом замечаются небольшие тормоза, например при вызове сообщения оно прорисовывается с задержкой. Когда QTableView без данных все отлично работает. Или, если только одна таблица заполнена данными, то тоже нормально работает.


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 11, 2011, 14:04
если я вызываю перед выводом сообщения
Код
C
qApp->processEvents();
 
то оно прям быстро отрисовывается. Только вот насколько это правильно использовать это при каждом вызове сообщения


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 14, 2011, 08:42
Подскажите пожалуйста, постоянный вызов:
Код
C
qApp->processEvents();
 
каждый раз при вызове диалога или сообщения ни к каким последствиям не приведет??
Просто я недавно занимаюсь QT, поэтому заранее извиняюсь возможно за глупые вопросы


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Whiplash от Ноябрь 14, 2011, 13:52
А что за сообщение?
Без кода трудно что-либо сказать.


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 15, 2011, 07:27
Вот текст программы

Код
C++ (Qt)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QSqlError>
 
MainWindow::MainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::MainWindow)
{
   ui->setupUi(this);
   createConnection();
 
   table1 = new QSqlTableModel(this);
   table1 -> setTable("sprUnGroup");
   table1 -> select();
   ui->tableView -> setModel(table1);
 
   table2 = new QSqlTableModel(this);
   table2 -> setTable("sprGroup");
   table2 -> select();
   ui->tableView_2->setModel(table2);
 
   table3 = new QSqlTableModel(this);
   table3 -> setTable("spr");
   table3->select();
   ui->tableView_3->setModel(table3);
   ui->tableView_3->setCornerButtonEnabled(true);
 
   connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(slotClick()));
}
 
MainWindow::~MainWindow()
{
   delete ui;
}
 
void MainWindow::changeEvent(QEvent *e)
{
   QMainWindow::changeEvent(e);
   switch (e->type()) {
   case QEvent::LanguageChange:
       ui->retranslateUi(this);
       break;
   default:
       break;
   }
}
 
void MainWindow::createConnection()
{
   db = QSqlDatabase::addDatabase("QODBC");
   db.setDatabaseName("DRIVER={SQL Server};SERVER=SRVSQL;Database=oms_nsi;Trusted_Connection=Yes;");
   if(!db.open())
     QMessageBox::critical(this,tr("Ошибка"),tr("Невозможно подключиться к базе данных\n") + db.lastError().text());
}
 
void MainWindow::slotClick(){
   qApp->processEvents();
   QMessageBox::question(0,"Вы уверены","Вы действительно хотите удалить запись?");
}
 


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 15, 2011, 14:49
Уважаемый Борис.
Давайте я вам объясню что вы делаете:

Форма загружается, прорисовывается и ... ждет когда окончатся функции, описанные в конструкторе. У вас в данном случае запрос к БД, который кстати может быть и более длительным(до 10-15 секунд), в зависимости от расположения базы, ее величины и величины канала связи.

Это плохо! Очень плохо.

Мой вариант (мб и не очень простой):

Код:
Ваш_Класс::Конструктор
{
    //  прописываем все ui методы (создание кнопок, формы, настройка их)
    // далее создаем поток загрузки (потомок от QThread в моем случае)
    LoadThread * thread = new QThread();
}

В самом же потоке вы вызываете все свои запросы, и передаете данные в основной поток (при этом интерфейс не виснет, пользователь видит программу с пустыми полями).

Получаете данные из потока, устанавливаете в View, показывая их пользователю. Пользователю так же можно вывести что-то типа  "Запрос к базам данных выполняется бззз...".

Дополнительная форма у вас я думаю работает аналогично ( в конструктор Вы все запихали). Потому и метод решения тот же.

PS по опыту знаю, лучше пользователь видит пустые поля с сообщением о загрузке сразу, чем видит тормоза при загрузке и думает, что тормозит ВАША программа, а не БД.


Добавлю - вызов processEvent  плох по 2 причинам
1) интерфейс все же тормозится и нервирует пользователя.
2) если же в моменты тормоза потыркать мышкой, полупить по клавиатуре и повазюкать экранчиком, то вполне возможен и завис/лаг/вылет/постоянный тормоз программы.


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: GreatSnake от Ноябрь 15, 2011, 15:05
Подскажите пожалуйста, постоянный вызов:
Код
C
qApp->processEvents();
 
каждый раз при вызове диалога или сообщения ни к каким последствиям не приведет??
Не приведёт.

Добавлю - вызов processEvent  плох по 2 причинам
1) интерфейс все же тормозится и нервирует пользователя.
2) если же в моменты тормоза потыркать мышкой, полупить по клавиатуре и повазюкать экранчиком, то вполне возможен и завис/лаг/вылет/постоянный тормоз программы.
Интересно, как на эти пункты может повлиять вызов processEvent()?


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 15, 2011, 15:47
Неправильное место для processEvent() = ужасные тормоза.

Очередь забивается в течении 2-3 секунд, после чего тормоза я тебе гарантирую на протяжении последующей минуты, если оставить ее в покое.

И добивающее фаталити - слишком частый вызов :) тормозит не так жестоко, но при выводе текста он начинает скакать и соответственно окошко тоже тормозит )


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: GreatSnake от Ноябрь 15, 2011, 17:03
Неправильное место для processEvent() = ужасные тормоза.

Очередь забивается в течении 2-3 секунд, после чего тормоза я тебе гарантирую на протяжении последующей минуты, если оставить ее в покое.

И добивающее фаталити - слишком частый вызов :) тормозит не так жестоко, но при выводе текста он начинает скакать и соответственно окошко тоже тормозит )
Хм, действительно какие-то ужасы... Может проблема не в processEvent(), а в чём-то другом, например, в дизайне? :)


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 16, 2011, 07:22
Спасибо, что ответили!!! У меня пока использование processEvent() не приводит ни к каким тормозам, а даже наоборот сообщение вылазиет мгновенно ... без его использования, при вызове сообщения прям видно как оно прорисовывается. Я же так понимаю эта функция выполняет все события и вызывает сообщение, а уже после вызова сообщения она перестает действовать и события выполняются в обычном порядке?


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 22, 2011, 09:27
Она обрабатывает все события в очереди. т.е. все твои движения мышкой, отрисовка виджета. ждет пока действия выполнятся и далее продолжает программу(функцию).


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 25, 2011, 08:07
Она обрабатывает все события в очереди. т.е. все твои движения мышкой, отрисовка виджета. ждет пока действия выполнятся и далее продолжает программу(функцию).
Спасибо за разъяснения!!! У меня тут еще один вопросик созрел, не буду новую тему создавать - сдеся спрошу ... при использовании функции resizeRowsToContents(), данные из базы грузятся заметно медленне и это при не очень большом кол-ве строк 250 где-то. И вот хочу спросить нормально ли это и возможно можно ли как-то избежать этого.


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 25, 2011, 08:57
Отвечаю - нужно по делу создавать новую тему, дабы мудрость моя и прочая могла быть найдена по теме Resize Rows Contents.

Отвечаю - эта функция ресайзит ВСЕ строки одновременно. Т.е. расчет содержимого, расчет нужного места и все все все.

Если у тебя в таблице данные не будут самопроизвольно меняться (к примеру какой нить параметр типа температуры и прочая),

то применяй при каждом добавлении строки resizeRowToContents(int номер строки). (заметь там будет ресайзиться 1 строка, а при вызове Rows будут все).

PS то же в 3 словах - Ты сейчас ломаешь веник, а нужно по прутику :)


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 25, 2011, 09:11
Если у тебя в таблице данные не будут самопроизвольно меняться (к примеру какой нить параметр типа температуры и прочая),
то применяй при каждом добавлении строки resizeRowToContents(int номер строки). (заметь там будет ресайзиться 1 строка, а при вызове Rows будут все).
В одной из таблиц у меня данные как-раз и меняются в зависимости от выбранной строки другой таблицы. И получается что при переходе с одной строки на другую одной таблицы, в другой данные меняются и каждый раз вызывается resizeRowsToContents(). Тут видимо уже ничего не поделаешь ... или не использовать эту функцию, что приводит не к очень красивлму отображению или использовать и наблюдать небольшую задержку ((((
А вот по поводу resizeRowToContents(int номер строки), как же мне ее применить при добавлении строки ... если после добавления мне нужно сначало обновить таблицу, что приводит к сбросу ранее подогнанных под размер контента строк. Такчто и при добавлении приходится использовать resizeRowыToContents


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 25, 2011, 10:32
Кхм. возможно ВЫ просто так думаете.

Меняются же не все 250+++ строк?

Если же  у вас, как я понимаю, вложенные таблицы(1 строке в верхней таблице соответвует целая таблица нижнего уровня).

Тогда решайте, что вам проще:
1) выяснить приемлимый и устраивающий всех размер ячеек и тупо задать его фиксированно(и не будет вызовов и тормозов).
2) применять функцию ресайза к тем строкам, которые видны. Там помоему даже функция есть выдающая видимые строки.
Т.е. вместо 250+ строк будет обновляться 10-40(я не вкурсе какая у ВАС таблица).
3) подумать что не так и как можно реализовать по другому :)


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 25, 2011, 12:48
Кхм. возможно ВЫ просто так думаете.
Меняются же не все 250+++ строк?
Ну я же после каждого добавления применяю метод select() к модели чтобы она обновилась.

Если же  у вас, как я понимаю, вложенные таблицы(1 строке в верхней таблице соответвует целая таблица нижнего уровня).
Тогда решайте, что вам проще:
1) выяснить приемлимый и устраивающий всех размер ячеек и тупо задать его фиксированно(и не будет вызовов и тормозов).
2) применять функцию ресайза к тем строкам, которые видны. Там помоему даже функция есть выдающая видимые строки.
Т.е. вместо 250+ строк будет обновляться 10-40(я не вкурсе какая у ВАС таблица).
3) подумать что не так и как можно реализовать по другому :)
я конечно больше скланяюсь ко второму методу решения ... правда функцию выдавающую видимые строки не могу найти. А даже если такая есть, то надо же еще сигнал скролла ловить при прокручивании и resiz-ить ячейки которые прокручиваются


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 25, 2011, 13:29
Цитировать
Ну я же после каждого добавления применяю метод select() к модели чтобы она обновилась.

Попробуйте использовать не select, а сигнал из модели beginInsertRow и endInsertRow. Они обновляют не всю таблицу, а только указанные строки.

Сам только на днях разбирался с моделями  и вынес 1 мудрость. Готов с тобой поделиться.

Если у тебя не меняются одновременно все елементы модели, но ты обновляешь всю модель, то ты делаешь что то неправильно :)


Пример-Дополнение:
Идеал:
Код:
Вставлена новая модель в View - обновление всей таблицы ~500 записей
Меняется строка - обновление 1 строки
Добавление строки - обновление 1 строки
Как я раньше реализовывал:
Код:
Вставлена новая модель в View - обновление всей таблицы~500 записей
Меняется строка - обновление всей таблицы~500 записей
Добавление строки - обновление всей таблицы ~500 записей

заинтересуешься можем посмотреть как улучшить твою модельку.


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 25, 2011, 13:53
Попробуйте использовать не select, а сигнал из модели beginInsertRow и endInsertRow. Они обновляют не всю таблицу, а только указанные строки.
Я сейчас конечно делаю также как Вы раньше реализовывали. Надо будет тоже поразбираться с этим. Но сейчас мне больше хочется разобраться как же мне быть с ложенной таблицей, сдесь больше заметнее тормоза, чем при добавлении напримерю. Спасибо, Bepec, за советы можт приведут они меня в нужное русло )))


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 25, 2011, 14:07
Буду рад помочь, к тому ж мне самому надо с этим разбираться вплоть до написания самому себе мануала :)


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 28, 2011, 07:31
Bepec, добрый день!!!!
Пытаюсь все-таки реализовать Ваш вариант resiz-ить только видимые ячейки. Покопавшись на форуме, нашел такую вещь .... что если ячейка становится видимой, то у нее идет запрос Qt::DisplayRole. И вот что у меня в итоге получилось после того как переопределил классы QSqlTableModel и QTableView

Код
C++ (Qt)
#ifndef MYSQLTABLEMODEL_H
#define MYSQLTABLEMODEL_H
 
#include <QSqlTableModel>
#include <QWidget>
class MySqlTableModel: public QSqlTableModel{
       Q_OBJECT
public:
       MySqlTableModel(QWidget *parent):QSqlTableModel(parent){
       }
       ~MySqlTableModel(){}
       QVariant data(const QModelIndex &index,int role = Qt::DisplayRole) const{
           QVariant value = QSqlQueryModel::data(index, role);
                if(role != Qt::DisplayRole)
                    return value;
                if(index.column()==1){
                    emit sig(index.row());
                   return value;
                }
                return value;
        }
    signals:
        void sig(int row)const;
 
};
#endif // MYMODEL_H
 

Код
C++ (Qt)
#ifndef MYVIEW_H
#define MYVIEW_H
 
#include <QtGui\QTableView>
#include <QMessageBox>
#include "mysqltablemodel.h"
 
class MyView: public QTableView{
Q_OBJECT
public:
       MyView(QWidget *parent):QTableView(parent){
       maxVisibleColumn = -1;
       }
~MyView(){}
       void setModel (QAbstractItemModel * model ){
           connect(model, SIGNAL(sig(int)), this, SLOT(slotResizeRow(int)));
           QTableView :: setModel(model);
       }
 
private:
     int maxVisibleColumn;
public slots:
     void slotResizeRow(int row){
         if(maxVisibleColumn < row){
             maxVisibleColumn = row;
             resizeRowToContents(maxVisibleColumn);
         }
     }
};
#endif // MIVIEW_H
 

Сдесь работает только в случае первой загрузки модели ... не могу никак поймать сигнал когда модель обновляется, т.е. когда к ней применяется метод select(), чтобы сбросить maxVisibleColumn и заново resizить. Уж не знаю на сколько правильно я сделал, реально первый раз пробую перегружать существующие методы ))))


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 28, 2011, 07:46
Реализация норм (на мой неискушенный взгляд), а как с быстродействием?

А попробовать сделать сигнал сброса значений и выдавать его одновременно с обновлением таблицы?
(если я правильно понял, что именно ты поймать не можешь :) )


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 28, 2011, 07:57
С быстродействием еще точн не могу сказать, пока не определюсь с обновлением ... но при загрузке прям быстрее  :)
А попробовать сделать сигнал сброса значений и выдавать его одновременно с обновлением таблицы?
(если я правильно понял, что именно ты поймать не можешь :) )
Пока у меня тоже только такие мысли. Просто хотелось бы сразу все в классе MyView реализовать и не задумываться об этом в основном коде. Вот и думаю как основными методами это сделать, может модель испускает какой-то сигнал или в каком-то методе что-то меняется при обновлении. Щас еще порыскаю  :)


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 28, 2011, 08:07
Нашел сигнал modelReset(), возможно то что мне нужно ... но он private. Может его можно как-то использовать?


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 28, 2011, 08:19
Пробуй, смотри когда он вызывается.Обрати так же внимание на modelAboutToBeReset. Тоже самое, но перед изменением насколько я понял :)


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: chester от Ноябрь 28, 2011, 09:01
Этот сигнал походу испускается при setTable, а не при select() ((


Название: Re: Сразу несколько таблиц с данными на одной форме
Отправлено: Bepec от Ноябрь 28, 2011, 09:27
Думаю тебе проще разнести по сигналу. А так очевидных и предъопределенных сигналов я больше не знаю :)