Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Модель/Представление _ QAbstractItemView, или внутренности Qt

Автор: Litkevich Yuriy 8.2.2009, 16:19

В классе QAbstractItemView есть метод setModel(QAbstractItemModel *model)

Цитата
/*!
Sets the \a model for the view to present.

\bold{Note:} This function will also create and set a new selection model,
replacing any previously set with setSelectionModel(), but the old selection
model will not be deleted
.

\sa selectionModel(), setSelectionModel()
*/

и подтверждение сказаному:
setSelectionModel(new QItemSelectionModel(d->model, this));


Для меня остается загадкой:
1) либо почему старая не удаляется?
2) либо почему старая не используется?

В примере %QTDIR%\demos\sqlbrowser при выполнении запроса устанавливается для табличного представления QSqlQueryModel, а при просмотре таблицы, для этого же представления, устанавливается QSqlTableModel. Человек реально много раз может переключаться с одной работы на другую. Тем самым модели выделения будут создаваться вновь и вновь. Как-то странно это все.

Автор: SABROG 8.2.2009, 17:26

Я мало что понял. Вопрос заключается в том почему тролли не сделали автоматическое удаление модели выделения и почему не используют старую модель выделения (старая это какая, которая была заменена новой, но осталась висеть в памяти и должна использоваться, если конструктор новой не сработал или что?).

Автор: Litkevich Yuriy 8.2.2009, 17:42

Цитата(SABROG @ 8.2.2009, 20:26) *
старая это какая, которая была заменена новой
да

Автор: SABROG 8.2.2009, 18:17

Кстати интересно. Написано, что setModel каждый раз устанавливает новую QItemSelectionModel, т.е. старая модель все-таки должна удаляться Qt иначе будет утечка памяти...

Автор: Litkevich Yuriy 8.2.2009, 18:27

Цитата(SABROG @ 8.2.2009, 21:17) *
т.е. старая модель все-таки должна удаляться Qt
этого нигде не написано, читай мой пост, там выделено жирным.


П.С. версия Qt в моей подписи

Автор: SABROG 8.2.2009, 19:31

В 4.4.3 ситуация таже. Все экземпляры QItemSelectionModel удаляются только в момент удаления компонентов на базе QAbstractItemView, т.к. именно он является предком. Т.е. только когда удаляются QColumnView, QHeaderView, QListView, QTableView, и QTreeView. Отсюда можно сделать вывод, что setModel в цикле на одну вьюху рано или поздно закончится плачевно. Я решил провести эксперимент таким образом:

        QTreeView *tree = new QTreeView(this);
        forever
        {
                tree->setModel(0);
        }


Судя по исходникам нулевой указатель вместо модели должен ставить статическую дефолтную модель при этом создавать каждый раз новую selectedModel. Поедание памяти снимал с диспетчера задач:



Затем я изменил исходник таким образом:

        forever
        {
        QTreeView *tree = new QTreeView(this);
                tree->setModel(0);
                delete tree;
        }


Поедание памяти продолжилось, но на этот раз не существенно, где-то на 10-50кб в секунду.

Автор: Константин 9.2.2009, 10:16

страшного ничего в этом нет. просто на момент установки новой модели "старая" селекшн-модель может ещё использоваться и, поскольку мы не хотим сегфолта, модель не удаляем (подобное часто встречается в сорцах кутэ) - на мой взгляд это лучше, чем пол-дюжины проверок в каждом методе (привет, гтк)!
если нужно часто "передёргивать" модель-источник и программист твёрдо уверен, что селекшн-модель в момент установки модели-источника нигде не используется, программист может смело делать так:

        QTreeView *tree = new QTreeView(this);
        forever
        {
                QItemSelectionModel* sm = tree->selectionModel();
                tree->setModel(0);
                sm->deleteLater;
        }

Автор: SABROG 9.2.2009, 11:39

Интересно почему Qt сама не делает deleteLater(). Или почему нет предупреждения о возможной утечке памяти. Скорее всего потому, что вьюха не рассчитана на такое использование модели. Видимо предполагается, что модель должна быть одна-две и вся работа по заполнению/очистки модели должна происходить только с одним экземпляром.

Автор: Litkevich Yuriy 9.2.2009, 12:02

Цитата(SABROG @ 9.2.2009, 14:39) *
Интересно почему Qt сама не делает deleteLater().
Цитата(Гость_Константин_* @ 9.2.2009, 13:16) *
"старая" селекшн-модель может ещё использоваться


Цитата(SABROG @ 9.2.2009, 14:39) *
Или почему нет предупреждения о возможной утечке памяти.
Цитата(Litkevich Yuriy @ 8.2.2009, 19:19) *
\bold{Note:} This function will also create and set a new selection model,
replacing any previously set with setSelectionModel(), but the old selection
model will not be deleted.
http://doc.crossplatform.ru/qt/4.3.5/qabstractitemview.html#setModel

Автор: SABROG 9.2.2009, 12:10

Цитата(Litkevich Yuriy @ 9.2.2009, 11:59) *
"старая" селекшн-модель может ещё использоваться

ну с deleteLater она удалится после использования, когда управление вернется в режим "ожидания"

Цитата(Litkevich Yuriy @ 9.2.2009, 11:59) *
but the old selection
model will not be deleted.

Да, но тут как-то сказано вскользь, намеками. Тут не сказано, что об удалении должен заботится пользователь.

Вот какая еще штука есть http://doc.trolltech.com/4.4/qobjectcleanuphandler.html
Если ядро сама удалит какой-то QObject, то он автоматически удаляется из списка.

Автор: Константин 9.2.2009, 12:44

Цитата(SABROG @ 9.2.2009, 12:10) *
Цитата(Litkevich Yuriy @ 9.2.2009, 11:59) *
"старая" селекшн-модель может ещё использоваться

ну с deleteLater она удалится после использования, когда управление вернется в режим "ожидания"

        QTreeView *tree = new QTreeView(this);
        forever
        {
                QItemSelectionModel* sm = tree->selectionModel();
                tree->setModel(0);
                // предполагаем, что в setModel(...) выполнится sm->deleteLater;
                tree->setSelectionModel(sm); // типа, восстановили состояние выбора до сброса модели
        }

ы?


Цитата(SABROG @ 9.2.2009, 12:10) *
Вот какая еще штука есть http://doc.trolltech.com/4.4/qobjectcleanuphandler.html
Если ядро сама удалит какой-то QObject, то он автоматически удаляется из списка.

это тупо кучка QPointer<QObject>. полезной нагрузки мало.

Автор: Litkevich Yuriy 9.2.2009, 13:29

я думаю, что можно было бы продолжить использовать имеющуюся модель выбора. Т.к. представления должны работать в главном потоке и как следствие связанные с ними модели. Поэтому если програмист меняет модель данных, то одновременно с этим он не работает с моделью выбора. Хотя, в прочем, я еще полноценно с модель/представление не работал, может в этом и нет особой надобности.

Автор: SABROG 9.2.2009, 13:59

Цитата(Гость_Константин_* @ 9.2.2009, 12:44) *
ы?


А где ты увидел выход в eventloop? Eventloop прерывается при входе в метод который вызывает setModel(), затем должен восстанавливаться уже после forever (если его убрать конечно). Там объекты и удалятся.

Цитата(Гость_Константин_* @ 9.2.2009, 12:44) *
это тупо кучка QPointer<QObject>. полезной нагрузки мало.

Этот класс для отладочных целей, позволяет контролировать/наблюдать жизнь объектов. Это не просто список, он динамический. Например ты добавил кучу кнопок на форму и решил отследить удалит ли их parent. После удаления родительской формы в этом списке не должно остаться ни одного объекта иначе мы делает вывод, что у нас утечка памяти или косяк где-то (например забыли передать предка).

Меня еще вот какой вопрос волнует. В Qt есть сигнал destroyed(), а вот created() нет. Интересно, есть ли возможность без наследования получить список всех QObject'ов в программе или по крайней мере создать такой список? При этом не обязательно, что QObject имеет parent'a или является QWidget'ом.

Автор: Litkevich Yuriy 9.2.2009, 14:14

Цитата(SABROG @ 9.2.2009, 16:59) *
Меня еще вот какой вопрос волнует. В Qt есть сигнал destroyed(), а вот created() нет.
лучше отдельную тему для этого

Цитата(SABROG @ 9.2.2009, 16:59) *
А где ты увидел выход в eventloop? Eventloop прерывается при входе в метод который вызывает setModel(), затем должен восстанавливаться уже после forever (если его убрать конечно). Там объекты и удалятся.
я думаю под Ы это и имелось в виду, когда выйдем в обработку событий, объект удалится, а мы его уже пользуем

Автор: Константин 9.2.2009, 14:25

> А где ты увидел выход в eventloop?
согласен, с примером оплошал. но и tree->setSelectionModel(sm) не обязательно может выполнятся синхронно :)
правда, это уже абсурдинкой попахивает...наверное, просто не рассчитана вьюха на подобные передёргивания источника - и всё тут...


> Интересно, есть ли возможность без наследования получить список всех QObject'ов в программе или по крайней мере создать такой список? При этом не обязательно, что QObject имеет parent'a или является QWidget'ом.

see src/corelib/kernel/qobject.cpp:

/*
let's see src/corelib/kernel/qobject.cpp:

Q_GLOBAL_STATIC (QObjectSet, allObjects)

extern "C" Q_CORE_EXPORT void qt_addObject(QObject *object)

   QWriteLocker locker(qt_object_read_write_lock());
   QObjectSet *set = allObjects();
   if (set)
       set->insert(object);

//...
QObject::QObject(QObject *parent)
   : d_ptr(new QObjectPrivate)

   Q_D(QObject);
   qt_addObject(d_ptr->q_ptr = this);
//...
*/

это единственный список всех созданных объектов (с родителями и без), но в ТТ сказали, что его в будущих версиях будут убирать.

Автор: SABROG 9.2.2009, 14:38

Цитата(Litkevich Yuriy @ 9.2.2009, 14:14) *
лучше отдельную тему для этого

Раздели, если есть мысли по этому поводу.

Цитата(Litkevich Yuriy @ 9.2.2009, 14:14) *
я думаю под Ы это и имелось в виду, когда выйдем в обработку событий, объект удалится, а мы его уже пользуем

А в противном случае у нас другой косяк может возникнуть. Предположим мы получаем selectionModel и сохраняем указатель где-нибудь в другой переменной, затем делаем setModel(), а потом как ни в чем не бывало пытаемся использовать старую selectionModel. В итоге она будет возвращать всегда одни те же данные о выборе, что не будет соответствовать правде. И уйти от косяка кроме как прочитав предупреждение в ассистенте никак нельзя.

Цитата(Гость_Константин_* @ 9.2.2009, 14:25) *
это единственный список всех созданных объектов (с родителями и без), но в ТТ сказали, что его в будущих версиях будут убирать.


allObjects не помечен как extern, стало быть доступа к нему напрямую нету... Или у вас есть пример как достучаться?

Автор: Константин 9.2.2009, 15:23

я и не говорил, что к нему достучаться. в лучшем случае из него можно выдоить виджеты без родителя...
но в отладочных целях можно влезть в код и наделать там гадостей :)

Автор: Дмитрий - 2.8.2011, 14:52

Подскажите пожалуйста что выбрать? Устанавливаю в TableView новую ItemSelectionModel. Так как старая ItemSelectionModel больше не нужна, то требуется её удалить. Сейчас в документации последних версий уже описывается в каких случаях это нужно делать и предлагается для этого два способа:

 QItemSelectionModel *OldSelectionModel = view->selectionModel();
view->setSelectionModel(new MyItemSelectionModel(view->model));
delete OldSelectionModel;

или с помощью deleteLater():

 view->selectionModel()->deleteLater();
view->setSelectionModel(new MyItemSelectionModel(view->model));
          а может быть правильно так:
QItemSelectionModel *OldSelectionModel = view->selectionModel();
view->setSelectionModel(new MyItemSelectionModel(view->model));
OldSelectionModel->deleteLater();

Чем отличаются эти способы и какой лучше выбрать?

Автор: wiz29 2.8.2011, 15:43

разница именно в моменте удалении непосредственно самого объекта, в случае оператора delete объект будет удален сразу, в случае удаления посредством вызова deleteLater объект удалится, в момент передачи управления основному циклу обработки сообщений приложения, т.е. при таком вызове указатель на объект как правило еще валиден в рамках вызывающего участка кода. Что лучше использовать уже дело вкуса, если вариант с вызовом delete решает нужную задачу, то я выберу его.

Автор: Дмитрий - 2.8.2011, 17:07

В документации для QAbstractItemView::setSelectionModel предлагается использовать deleteLater(), но вероятно имеется ввиду общий, универсальный случай. В моём случае, после задания TableView->setModel, я сразу в TableView->setSelectionModel задаю MyItemSelectionModel, а ItemSelectionModel созданная по умолчанию мне совсем не нужна и, поэтому я думаю, что её можно удалить с помощью просто delete.

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)