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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: SqlTableModel/TableView тормоза  (Прочитано 6730 раз)
igorko
Гость
« : Август 04, 2006, 16:46 »

Я сделал SqlTableModel, TableView и Delegate.

Пока записей не много, то все работает нормально.
Когда назаписывал около 1500 записей - стало ужасно тормозить Грустный
(Сами запросы выполняются не более 2 сек в pgAdmine)

Посоветуйте, пожалуйста, как узнать где нужно оптимизировать.
Записан
Alexei
Гость
« Ответ #1 : Август 05, 2006, 07:42 »

Какой режим debug или release? Что в делегате? Подробнее, пожалуйста.
Записан
igorko
Гость
« Ответ #2 : Август 06, 2006, 14:48 »

Спасибо Alexei, за намерение помочь.

Режим - debug

Вот весь делегат:

/*
    delegate.cpp

    A delegate that allows the user to change values from the model
    using a combo box widget.
*/

#include <QtGui>
#include <QtSql>

#include "delegate.h"
#include "mymodels.h"


MyDelegate::MyDelegate(QObject *parent)
: QItemDelegate(parent)
{
//   installEventFilter(this);
}

QWidget *MyDelegate::createEditor(QWidget *parent,
    const QStyleOptionViewItem & option,
    const QModelIndex & index) const
{
   MySqlTableModel *m = (MySqlTableModel*)(index.model());

   if ( m->isForeignKey( index.column() ) )
   {
      QString query = QString ("SELECT %1 FROM %2") // ORDER BY %1")
            .arg( m->getForeignFieldName( index.column() ) )
            .arg( m->getForeignTableName( index.column() ) );

      QSqlQuery q(query);
      QStringList sl;
      while (q.next())
         sl += q.value(0).toString();

       MyComboBox *comboEditor = new MyComboBox(sl, parent);
      comboEditor->setObjectName("ComboEditor");
      comboEditor->installEventFilter(const_cast<MyDelegate*>(this));

      return comboEditor;
   }

   QDateEdit *dateEditor;
   QTextEdit *textEditor;
   QLineEdit *lineEditor;

   switch ( m->getFieldType( index.column() ) )
   {
      case QVariant::Date:
         dateEditor = new QDateEdit(parent);
         dateEditor->setDisplayFormat("dd.MM.yyyy");
         return dateEditor;
      case QVariant::String:
         if ( m->getFieldLength( index.column() ) == -1 )      // if length = -1  TEXT field
         {
            textEditor = new QTextEdit(parent);
            textEditor->setObjectName("TextEditor");
            return textEditor;
         }
//000
//         else
//         {
//            lineEditor = new QLineEdit(parent);
//            lineEditor->setObjectName("LineEditor");
//            return lineEditor;
//         }
   }

   return QItemDelegate::createEditor(parent, option, index);
}

void MyDelegate::closeEditor ( QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
{
   if(editor->objectName() == "ComboEditor")
      removeEventFilter(this);
   QItemDelegate::closeEditor(editor, hint);
}

void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
   MySqlTableModel *m = (MySqlTableModel*)(index.model());

   MyComboBox *comboBox;
   QDateEdit *dateEdit;
   QTextEdit *textEditor;
   QLineEdit *le;
   QString value;
   double d;

   if (m->isForeignKey(index.column()))
   {
         value = index.model()->data(index, Qt::DisplayRole).toString();
          comboBox = static_cast<MyComboBox*>(editor);
         comboBox->updateSearch(value);
         (const_cast<MyDelegate*>(this))->setOldValue (value);
         return;
   }

   switch ( m->getFieldType( index.column() ) )
   {
      case QVariant::Date:

         value = index.model()->data(index, Qt::DisplayRole).toString();
          dateEdit = static_cast<QDateEdit*>(editor);
         dateEdit->setDisplayFormat("yyyy-MM-dd");
         if (value != "") dateEdit->setDate(QDate::fromString(value, "yyyy-MM-dd"));
         else dateEdit->setDate (QDate::currentDate());
//         dateEdit->selectAll();
         return;

      case QVariant::String:
         if ( m->getFieldLength( index.column() ) == -1 )   // if length=-1 - we have text field
         {
            value = index.model()->data(index, Qt::DisplayRole).toString();
            textEditor = static_cast<QTextEdit*>(editor);
            textEditor->setPlainText(value);
            textEditor->selectAll();
            return;
         }
         le = static_cast<QLineEdit*>(editor);
         le->setText(index.model()->data(index, Qt::DisplayRole).toString());
         le->selectAll();
         return;

      case QVariant::Double:
      case QVariant::Int:
         d = index.model()->data(index, Qt::DisplayRole).toDouble();
         le = static_cast<QLineEdit*>(editor);
         le->setText(QString("%1").arg(d));
         le->selectAll();
         return;
   }
   return QItemDelegate::setEditorData(editor, index);
}

void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                   const QModelIndex &index) const
{
   MySqlTableModel *m = (MySqlTableModel*)(index.model());

   QTableView *v = static_cast<QTableView*>(editor->parent()->parent());

   MyComboBox *comboBox;
   QDateEdit *dateEdit;
   QTextEdit *textEditor;
   QLineEdit *lineEditor;

   QString value;

   if (m->isForeignKey(index.column()))
   {
         comboBox = static_cast<MyComboBox*>(editor);
         value = comboBox->currentText();

         if (comboBox->isInFullList(value) == TRUE)
            model->setData(index, value);
         else
         {
            QMessageBox::information(editor,"MyDB", "В списку немає такого значення!");
            model->setData(index, oldValue);
         }
//         v->resizeColumnToContents(index.column());

         return;
   }

   switch ( m->getFieldType( index.column() ) )
   {
      case QVariant::Date:
         dateEdit = static_cast<QDateEdit*>(editor);
         value = dateEdit->text();
         model->setData(index, value);
         return;
      case QVariant::String:
         if ( m->getFieldLength( index.column() ) == -1 )   // if length = -1  TEXT field
         {
            textEditor = static_cast<QTextEdit*>(editor);
            value = textEditor->toPlainText();
            model->setData(index, value);
            return;
         }
//000
//         else
//         {
//            lineEditor = static_cast<QLineEdit*>(editor);
//            value = lineEditor->text();
//            model->setData(index, value);
//            return;
//         }
   }

   return QItemDelegate::setModelData(editor, model, index);
}

void MyDelegate::updateEditorGeometry(QWidget *editor,
    const QStyleOptionViewItem &option, const QModelIndex &index) const
{
   MySqlTableModel *m = (MySqlTableModel*)(index.model());

   QWidget *w = static_cast<QWidget*>(editor->parent());

   QRect r = option.rect;
//   int h = w->size().height() - editor->rect().height()*index.row();
//   r.setSize(QSize(200,(100 > h)?h:100));

//   if ( m -> getFieldType( (index.column() ) == QVariant::String) && (m -> getFieldLength ( index.column() ) == -1 ) )
//      editor->setGeometry(r); // for TEXT field (length == -1)
//   else
      editor->setGeometry(option.rect);
}


bool MyDelegate::eventFilter(QObject *obj, QEvent *event)
{
   if (event->type() == QEvent::KeyPress)
   {
      QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
      if (keyEvent->key() == Qt::Key_Return)
      {
         if (obj->objectName() == "ComboEditor")
         {
            MyComboBox *comboBox = static_cast<MyComboBox*>(obj);
            if(comboBox->count() != 1)
            {
               comboBox->showPopup();
               return true;
            }
         }
         else
            if(obj->objectName() == "TextEditor")
            {
               QTextEdit *textEdit = static_cast<QTextEdit*>(obj);
               textEdit->insertPlainText("\n");
               return true;
            }
      }
   }
   return QItemDelegate::eventFilter(obj, event);
}
Записан
Alexei
Гость
« Ответ #3 : Август 07, 2006, 08:08 »

Предлагаю следующее.
Сначала попробуй собрать проект в режиме release и выяснить на скольких записях повляются тормоза. Например, у меня в режиме release (без каких-либо своих делегатов) все шустро работает с количеством записей ~80000.
Затем потихоньку одну за одной подключай функции делегата.

И еще, что у тебя в MySqlTableModel::data(const QModelIndex& index, int role = Qt::DisplayRole)?
Записан
igorko
Гость
« Ответ #4 : Август 07, 2006, 10:04 »

Еще раз спасибо Alexei!

Я попробовал создать QSqlQueryModel/QTableView с таким же запросом и все работает быстро даже в режиме debug. Поэтому я думаю, что проблема в моей реализации.

Вот моя data:

QVariant MySqlTableModel::data (const QModelIndex & index, int role) const
{
   if (!index.isValid())
      return QVariant();

   QSqlField field;

   QString val;

   QDate date;

   int fieldNo = index.column();
   if (hasPKey) fieldNo ++;

   if (index.row() < query -> size ())            // index is in query size
   {
      if (updatedRecords.contains( index.row() ) ) // if index is in the updatedRecords
      {
         field = updatedRecords.value(index.row()).field( fieldNo );
      }
      else
         if (query->seek(index.row()) == true)   // if index is inside the query
         {
            field = query -> record().field( fieldNo );
         }
   }
   else                                 // if index is in the newRecords
      if ( (index.row() - query->size() ) < newRecords.size() ) // !!!!!! CHECK <=
      {
         field = newRecords.value(index.row() - query->size() ).field( fieldNo );
      }

   switch (role)
   {
   case Qt::DisplayRole:
      switch ( field.type() )
      {
      case QVariant::Double:
         val.sprintf("%.2f",field.value().toDouble());
         return val;
      case QVariant::Date:
         return field.value();
//         date = QDate::fromString(field.value().toString(), "yyyy-MM-dd");
//         return date.toString("dd.MM.yyyy");
      }
      
      return field.value().toString();

   case Qt::TextAlignmentRole:

      return (field.type() == QVariant::Double || field.type() == QVariant::Int) ?
              QVariant(Qt::AlignRight | Qt::AlignVCenter)
            : QVariant(Qt::AlignLeft | Qt::AlignVCenter);
   }
   return QVariant ();
}
Записан
Alexei
Гость
« Ответ #5 : Август 07, 2006, 10:53 »

field = query -> record().field( fieldNo);

Скорее всего, в этой строчке источник тормозов. Обращение query->record() - медленное, я уже сталкивался с этим.
Записан
igorko
Гость
« Ответ #6 : Август 07, 2006, 17:25 »

Скорее всего, Вы правы Alexei.
Большая часть "тормоза" убралась когда я убрал эту строчку.
Но как же мне заполнять модель из результата запроса без этой ф-ции?

По Вашим ответам видно, что Вы хорошо знакомы с темой.
Буду очень благодарен за хороший совет.
А то у меня аж руки опустились, когда увидел что и на Qt можно сделать то что невозможно использовать 8-|
Записан
Alexei
Гость
« Ответ #7 : Август 07, 2006, 20:21 »

Заполнять модель данными можно с помощью функции value() класса QSqlQuery, минуя вызов record(). Например, query->value(fieldNo).toString()

Остается сделать так, чтобы информация о поле была доступна внутри функции MySqlTableModel::data(). Функцию record() надо вызвать один раз сразу же после выполнения запроса:

query->exec(Тут стоит запрос);
rec = query.record();  //rec должен быть объявлен в классе MySqlTableModel

теперь rec можно использовать в функции data для получения информации о полях записи, а вот данные брать, как уже было упомянуто, с помощью query->value(индекс поля) без использования query->record()

Еще один момент. Возможно будет проще сделать MySqlTableModel наследником от QSqlQueryModel и функция data():

QVariant MySqlTableModel::data(const QModelIndex & index, int role) const
{
  QVariant v = QSqlQueryModel::data(index, role);
  //далее работать с переменной v
  .....
}

В этом случае не понадобится переменная query, так как в классе QSqlQueryModel есть функция SetQuery(подробнее можно посмотреть в документайии по классу QSqlQueryModel)
Записан
bigirbis
Гость
« Ответ #8 : Август 08, 2006, 08:46 »

Цитировать
QSqlQuery q(query);
QStringList sl;
while (q.next())
sl += q.value(0).toString();

MyComboBox *comboEditor = new MyComboBox(sl, parent);


ИМХО, не стоит заполнять ComboBox так явно. Думаю для начала надо создать модель, а потом ее уже передать в ComboBox, т.о. источник данных будет общий.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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