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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: После setData сделать refresh QSqlQueryModel  (Прочитано 10904 раз)
Alex_C
Гость
« : Май 11, 2012, 15:39 »

Определил свою модель на основе QSqlQueryModel. Чтобы данные в TableView можно было редактировать, переопределил метод setData у наследника QSqlQueryModel.

Код:
bool LogModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.column() < 1)
        return false;

    QModelIndex primaryKeyIndex = QSqlQueryModel::index(
                index.row(), 0);
    int id = QSqlQueryModel::data(primaryKeyIndex).toInt();

    bool ok;
    QSqlQuery query;
    if (index.column() > 1)
    {
        QString fieldName = getFieldNameByIndex(index.column());
        query.prepare("UPDATE " + logName + " SET " + fieldName +
                      " = ? WHERE KeyField = ?");
        query.addBindValue(value.toString());
        query.addBindValue(id);
    }
    ok = query.exec();
    refresh(); // Проблема вот здесь
    return ok;
}

Данные в базу вносятся, но естественно пока для унаследованной модели на refresh() не сделаешь SELECT FROM ... в QTableView отображаются данные что были. Если делать селект всей таблицы, а она не маленькая, то после редактирования получается задержка. Есть ли (а я уверен, что есть) возможность избежать этой задержки?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Май 11, 2012, 15:44 »

http://doc-snapshot.qt-project.org/4.8/qabstractitemmodel.html#dataChanged
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alex_C
Гость
« Ответ #2 : Май 11, 2012, 16:59 »


Да спасибо, но я это видел, но так до конца не понял как этим воспользоваться именно в моем случае.
Пытался сделать так :

Код:
bool LogModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.column() < 1)
        return false;

    QModelIndex primaryKeyIndex = QSqlQueryModel::index(
                index.row(), 0);
    int id = QSqlQueryModel::data(primaryKeyIndex).toInt();

    bool ok;
    QSqlQuery query;
    if (index.column() > 1)
    {
        QString fieldName = getFieldNameByIndex(index.column());
        query.prepare("UPDATE " + logName + " SET " + fieldName +
                      " = ? WHERE KeyField = ?");
        query.addBindValue(value.toString());
        query.addBindValue(id);
    }
    ok = query.exec();
    QSqlQueryModel::setData(index, value); // В нашей модели меняем данные
    emit dataChanged(index, index); // Вот мы дали сигнал на изменение данных
    return ok;
}

И далее отлавтиваем сигнал dataChanged в QTableView

Код:
void LogTableView::slot_modelDataChange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
    qDebug() << "Row = " << topLeft.row() << " Col = " << bottomRight.column();
    reset(); // Коммпанда перечитать данные из модели?
}

Все отлавливается, но данные в QTableView так и не изменились.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #3 : Май 11, 2012, 19:14 »

Ловить сигнал не нужно, вьюха сама должна его обработать.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alex_C
Гость
« Ответ #4 : Май 12, 2012, 12:13 »

Все таки не получается.
А вот эта строка правильная -
Код:
QSqlQueryModel::setData(index, value);

Я правильно в модели данные меняю?
Записан
Странник
Гость
« Ответ #5 : Май 12, 2012, 12:20 »

Все таки не получается.
А вот эта строка правильная -
Код:
QSqlQueryModel::setData(index, value);

Я правильно в модели данные меняю?
есть подозрение, что QSqlQueryModel::setData, как бы это помягче, does nothing. и возвращать false должна, по идее. вам нужно написать свою реализацию setData и при успешном изменении эмиттить dataChanged().
Записан
Alex_C
Гость
« Ответ #6 : Май 12, 2012, 13:55 »

См мои сообщения 1 и 3 - так я setData и переопределяю у своей модели - LogModel.
В строках
Код:
QSqlQuery query;
    if (index.column() > 1)
    {
        QString fieldName = getFieldNameByIndex(index.column());
        query.prepare("UPDATE " + logName + " SET " + fieldName +
                      " = ? WHERE KeyField = ?");
        query.addBindValue(value.toString());
        query.addBindValue(id);
    }
    ok = query.exec();

я как раз заношу физически данные в базу. А теперь задача - обновить модель, которая показывается, не перечитывая все данные опять с диска.
И Пантер, как я понимаю, совет абсолютно правильный дал. Но вот конкретно реализовать пока не получилось.
Те примеры, что я в инете нашел - там все на примере QStringModel сделано - что естественно на порядок проще.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #7 : Май 12, 2012, 13:57 »

Не хочу тебя расстраивать, но походу не получится - QSqlQueryModel кеширует у себя данные. Так что, походу, придется писать свою модель.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alex_C
Гость
« Ответ #8 : Май 12, 2012, 14:01 »

Да, по ходу так и есть, ничего кроме этого не нашел -

Код:
bool EditableSqlModel::setData(const QModelIndex &index, const QVariant &value, int /* role */)
 {
     if (index.column() < 1 || index.column() > 2)
         return false;

     QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
     int id = data(primaryKeyIndex).toInt();

     clear();

     bool ok;
     if (index.column() == 1) {
         ok = setFirstName(id, value.toString());
     } else {
         ok = setLastName(id, value.toString());
     }
     refresh();
     return ok;
 }

 void EditableSqlModel::refresh()
 {
     setQuery("select * from person");
     setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
     setHeaderData(1, Qt::Horizontal, QObject::tr("First name"));
     setHeaderData(2, Qt::Horizontal, QObject::tr("Last name"));
 }

 bool EditableSqlModel::setFirstName(int personId, const QString &firstName)
 {
     QSqlQuery query;
     query.prepare("update person set firstname = ? where id = ?");
     query.addBindValue(firstName);
     query.addBindValue(personId);
     return query.exec();
 }

 bool EditableSqlModel::setLastName(int personId, const QString &lastName)
 {
     QSqlQuery query;
     query.prepare("update person set lastname = ? where id = ?");
     query.addBindValue(lastName);
     query.addBindValue(personId);
     return query.exec();
 }

Это из официальной доки... Только перечитывать все данные...
Но все таки по моему не может быть - задача то очень распространенная.
Записан
Alex_C
Гость
« Ответ #9 : Май 13, 2012, 10:38 »

В общем проблему решил. Не так конечно , как хотелось, но на данном этапе пойдет.
1. Все же отлавливаем emit dataChanged(index, index); в QTableView.
2. В QTableView
Код:
void LogTableView::slot_modelDataChange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
    qDebug() << "Row = " << topLeft.row() << "Column = " << topLeft.column();
    setUpdatesEnabled(false);
    QModelIndex i = model()->index(topLeft.row(), topLeft.column());
    tableModel()->setQuery(tableModel()->query().lastQuery());
    while(tableModel()->canFetchMore())
    {
        tableModel()->fetchMore();
        QCoreApplication::processEvents ();
    }
    setCurrentIndex(i);
    setUpdatesEnabled(true);
}

tableModel - это qobject_cast на мою переопределенную модель, т.к. abstractmodel не имеет методов setQuery.
Пока правда не понял - в некоторых случаях индекс устанавливается после редактирования правильно, а в некоторых случаях на 2 строки выше.
Записан
Alex_C
Гость
« Ответ #10 : Май 13, 2012, 10:49 »

Не хочу тебя расстраивать, но походу не получится - QSqlQueryModel кеширует у себя данные. Так что, походу, придется писать свою модель.

И все же - должно получиться. Я вот что подумал - QSqlTableModel - это наследник QSqlQueryModel. А у QSqlTableModel есть editStrategy - т.е. данные в модели меняются, а на диске - нет. Следовательно можно сделать так, как я и хочу - менять отдельно данные в модели и отдельно на диске. Осталось дело за малым - разобраться как это сделано в QSqlTableModel Улыбающийся
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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