Название: SqlTableModel/TableView тормоза Отправлено: igorko от Август 04, 2006, 16:46 Я сделал SqlTableModel, TableView и Delegate.
Пока записей не много, то все работает нормально. Когда назаписывал около 1500 записей - стало ужасно тормозить :( (Сами запросы выполняются не более 2 сек в pgAdmine) Посоветуйте, пожалуйста, как узнать где нужно оптимизировать. Название: SqlTableModel/TableView тормоза Отправлено: Alexei от Август 05, 2006, 07:42 Какой режим debug или release? Что в делегате? Подробнее, пожалуйста.
Название: SqlTableModel/TableView тормоза Отправлено: igorko от Август 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); } Название: SqlTableModel/TableView тормоза Отправлено: Alexei от Август 07, 2006, 08:08 Предлагаю следующее.
Сначала попробуй собрать проект в режиме release и выяснить на скольких записях повляются тормоза. Например, у меня в режиме release (без каких-либо своих делегатов) все шустро работает с количеством записей ~80000. Затем потихоньку одну за одной подключай функции делегата. И еще, что у тебя в MySqlTableModel::data(const QModelIndex& index, int role = Qt::DisplayRole)? Название: SqlTableModel/TableView тормоза Отправлено: igorko от Август 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 (); } Название: SqlTableModel/TableView тормоза Отправлено: Alexei от Август 07, 2006, 10:53 field = query -> record().field( fieldNo);
Скорее всего, в этой строчке источник тормозов. Обращение query->record() - медленное, я уже сталкивался с этим. Название: SqlTableModel/TableView тормоза Отправлено: igorko от Август 07, 2006, 17:25 Скорее всего, Вы правы Alexei.
Большая часть "тормоза" убралась когда я убрал эту строчку. Но как же мне заполнять модель из результата запроса без этой ф-ции? По Вашим ответам видно, что Вы хорошо знакомы с темой. Буду очень благодарен за хороший совет. А то у меня аж руки опустились, когда увидел что и на Qt можно сделать то что невозможно использовать 8-| Название: SqlTableModel/TableView тормоза Отправлено: Alexei от Август 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) Название: SqlTableModel/TableView тормоза Отправлено: bigirbis от Август 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, т.о. источник данных будет общий. |