crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> QTableView сортировка по нескольким колонкам одновременно и пример chap14 multisort из книги Земскова "Qt4 на примерах"
Steklova Olga
  опции профиля:
сообщение 14.6.2013, 18:02
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Здравствуйте :)
Понадобилось мне в QTableView отобразить записи таблицы БД, но отсортировать их не по одной колонке, как я раньше делала, а по нескольким одновременно.
(Есть, например, в таблице поля A, B, C, D, F1, F2. Надо отсортировать записи по возрастанию значений поля A, записи с одинаковым А надо еще отсортировать по возрастанию B, с одинаковыми A и B - по возрастанию C, с одинаковыми A, B и C - по возрастанию D.)

В книге Земскова есть пример multisort для QTableWidget. Там оператор, щелкая по заголовкам столбцов в том порядке, в каком хочет, выбирает, по каким колонкам надо отсортировать таблицу и как сортировать: по возрастанию или убыванию.

Мне в программе пока не требуется, чтобы оператор выбирал, по каким полям сортировать таблицу. Мне надо жестко задать сортировку таблицы по возрастанию полей A, B, C, D.
Как это сделать для QTableView?
Не хочется использовать QTableWidget, у меня везде в программе используются QTableView, для которых установлены модели. А у QTableWidget нет метода setModel, есть только setItem.

У меня, пока что, только одно предложение, как это можно сделать, но, по-моему, не самое удачное:
Поля A, B, C, D у меня целые, при этом я знаю, сколько цифр максимально могут содержать эти поля (A - max 4 цифры, B - 3, C - 1, D - 1). Если сделать вычисляемое поле F_AAAABBBCD и записать туда A*10000 + B*100 + C*10 + D, то отсортировав таблицу по возрастанию этого поля, получим сортировку по полям A, B, C, D.
Есть другие предложения? :rolleyes:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 15.6.2013, 14:36
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9656
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


См. Модели-посредники -> Пользовательские модели сортировки

Оговорка:
если первичная модель выбирает данные из БД, то нужно делать от неё наследника, т.к. БД возвращает не все данные (их может быть слишком много), а выдаёт их порциями.
В наследнике реализовать:
- либо запрос с сортировкой
- либо добавить собственную функцию для задания полей сортировки, например: setOrderField(QStringList), и при вызове select() у модели использовать эти поля.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 17.6.2013, 11:23
Сообщение #3


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Цитата(Litkevich Yuriy @ 15.6.2013, 14:36) *
См. Модели-посредники -> Пользовательские модели сортировки
эта ссылка не работает, вот точнее Модели-посредники
Но я еще не разобралась, как использовать QSortFilterProxyModel.

Цитата(Litkevich Yuriy @ 15.6.2013, 14:36) *
если первичная модель выбирает данные из БД, то нужно делать от неё наследника, т.к. БД возвращает не все данные (их может быть слишком много), а выдаёт их порциями.
В наследнике реализовать:
- либо запрос с сортировкой
- либо добавить собственную функцию для задания полей сортировки, например: setOrderField(QStringList), и при вызове select() у модели использовать эти поля.
извините, ничего не поняла

Предлагаю другой вариант. Если не использовать QSortFilterProxyModel, то, наверное, вот что можно сделать.
Я использую модель MyModel, унаследованную от QSqlTableModel, переопределяю в ней методы flags, data, setData. Эта модель позволяет указывать setSort только для одного поля таблицы.
Можно унаследовать модель MyModel не от QSqlTableModel, а от QSqlQueryModel. Такая модель позволит указать в setQuery сортировку по нескольким полям одновременно:
model = new MyModel(this);
model->setQuery("SELECT * FROM T_OBJ ORDER BY A, B, C, D");
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 17.6.2013, 19:05
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9656
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Steklova Olga @ 17.6.2013, 13:23) *
эта ссылка не работает
у меня работает


Цитата(Steklova Olga @ 17.6.2013, 13:23) *
Эта модель позволяет указывать setSort только для одного поля таблицы.
Цитата(Litkevich Yuriy @ 15.6.2013, 16:36) *
- либо добавить собственную функцию для задания полей сортировки, например: setOrderField(QStringList), и при вызове select() у модели использовать эти поля.

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 18.6.2013, 11:32
Сообщение #5


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Цитата(Litkevich Yuriy @ 15.6.2013, 14:36) *
В наследнике реализовать:

- либо добавить собственную функцию для задания полей сортировки, например: setOrderField(QStringList), и при вызове select() у модели использовать эти поля.
То есть, предлагаете переопределить метод select() у модели, унаследованной от QSqlTableModel ?
Вот что у меня получилось:
код в моем классе:
class MyModel : public QSqlTableModel
{
    Q_OBJECT
public:
    virtual bool select(); //?#
    ...

bool MyModel::select()
{
//    Q_D(QSqlTableModel); //не понимаю, что с этим делать, поэтому заремила
    QString query = selectStatement();
    if (query.isEmpty())
        return false;

    //меняю порядок сортировки
    query = query.toUpper();
    QString str_order = " ORDER ";
    int index = query.indexOf(str_order);
    int len = query.length();
    if (index >= 0)
        query.chop(len - index);
    query += " ORDER BY A, B, C, D";

    revertAll();
//    QSqlQuery qu(query, d->db); //не понимаю, что с этим делать,
    QSqlQuery qu(query);          //поэтому поменяла на это
    setQuery(qu);

//    if (!qu.isActive() || lastError().isValid()) {
//        // something went wrong - revert to non-select state
//        d->initRecordAndPrimaryIndex(); //не понимаю, что с этим делать, поэтому заремила
//        return false;
//    }
    return true;
}
код в исходникax:
class Q_SQL_EXPORT QSqlTableModel: public QSqlQueryModel
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QSqlTableModel)

public:
    virtual bool select();
    ...

bool QSqlTableModel::select()
{
    Q_D(QSqlTableModel);
    QString query = selectStatement();
    if (query.isEmpty())
        return false;

    revertAll();
    QSqlQuery qu(query, d->db);
    setQuery(qu);

    if (!qu.isActive() || lastError().isValid()) {
        // something went wrong - revert to non-select state
        d->initRecordAndPrimaryIndex();
        return false;
    }
    return true;
}
Запустила программу, вроде бы работает... Таблица сортируется по четырем полям A, B, C, D.
Меня смущает, что я заремила d->initRecordAndPrimaryIndex() :rolleyes:

Сообщение отредактировал Steklova Olga - 18.6.2013, 13:07
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 18.6.2013, 11:42
Сообщение #6


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9656
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


d->db - это просто БД (второй аргумент конструктора QSqlQuery)


Цитата(Steklova Olga @ 18.6.2013, 13:32) *
заремила
:lol:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 18.6.2013, 12:24
Сообщение #7


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Так я правильно поняла, что Вы
Цитата(Steklova Olga @ 18.6.2013, 11:32) *
предлагаете переопределить метод select() у модели, унаследованной от QSqlTableModel ?

В исходнике QSqlTableModel::select() я не понимаю:
- что такое Q_D(QSqlTableModel); и можно ли выкинуть эту строку при переопределении ?
- как добраться до d, чтобы обратиться к d->db ? Или никак не доберешься, и надо передавать db в наследуемый класс через параметр конструктора этого класса ? (хотя в моей программе можно обойтись вариантом QSqlQuery qu(query), так как у меня используется defaultConnection)
- что делать с d->initRecordAndPrimaryIndex() ? Как это написать в переопределенном методе select() ?
- переопределение select() ведет к необходимости переопределить еще какой-то метод в наследуемом классе ?

Цитата(Litkevich Yuriy @ 15.6.2013, 14:36) *
В наследнике реализовать:
- запрос с сортировкой
Это как ?

------------------------------------------
У меня появилось предложение, как сделать в QTableView сортировку по нескольким колонкам одновременно, если для QTableView установлена модель MySqlTableModel, унаследованная от QSqlTableModel.
Чтобы это сделать, переопределяем метод selectStatement()
, метод select() не переопределяем.
class MySqlTableModel : public QSqlTableModel
{
    Q_OBJECT
protected:
    virtual QString selectStatement() const;
    ...
    
QString MySqlTableModel::selectStatement() const
{
    QString query = QSqlTableModel::selectStatement();
    
    query = query.toUpper();
    int index = query.indexOf(" ORDER ");
    if (index >= 0)
        query.chop(query.length() - index);
    query += " ORDER BY "
             "A, B, C, D";

    return query;
}
По-моему, этот вариант простой и правильный. Проверите? У меня работает :D


Сообщение отредактировал Steklova Olga - 18.6.2013, 14:30
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 18.6.2013, 18:50
Сообщение #8


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9656
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Steklova Olga @ 18.6.2013, 14:24) *
Так я правильно поняла, что Вы ...
предлагаете переопределить метод select() у модели, унаследованной от QSqlTableModel ?
нет.
идея была простая:
Цитата(Litkevich Yuriy @ 15.6.2013, 16:36) *
добавить собственную функцию для задания полей сортировки, например: setOrderField(QStringList)
дальше, нужно было заглянуть в метод select() чтобы понять, как на него влиять. Из приведённого тобой кода видно, что метод select() использует в качестве запроса результат метода selectStatement() его нужно будет переопределить,
но ты уже сама до этого дошла:
Цитата(Steklova Olga @ 18.6.2013, 14:24) *
Чтобы это сделать, переопределяем метод selectStatement(), метод select() не переопределяем.
осталось сделать метод setOrderField(QStringList), который позволит сделать твою модель гибче (её не надо будет переписывать в будущем)

Цитата(Steklova Olga @ 18.6.2013, 14:24) *
В исходнике QSqlTableModel::select() я не понимаю:
- что такое Q_D(QSqlTableModel); ...
- как добраться до d, чтобы обратиться к d->db ? ...
- что делать с d->initRecordAndPrimaryIndex() ? ...
...
d, Q_D(QSqlTableModel) - это из области d-указателей/Pimpl
Они используются, чтобы создать вспомогательный класс описывающий "потраха" данного класса. А он, в свою очередь, чтобы обеспечить двоичную совместимость разделяемых библиотек (dll-ок для Виндовоза) от версии к версии.
Положим у нас есть QCore.dll версии 4.4 если мы его усовершенствуем до версии 4.5, то хотим, чтобы программы собранные с 4.4 работали и с dll-ками 4.5.
Но всякий раз когда мы добавляем виртуальный метод в класс, результат компиляции (двичный фал dll-ки) будет несовместим с предыдущей версией и программа скомпилированная с предыдущей версией dll-ки откажется работать.

Для сохранения возможности изменения класса не изменяя его интерфейс придумали вспомогательный класс в котором вся каша и варится.

d-указатели в официальной Qt Wiki (англ.)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 29.1.2020, 17:42