Russian Qt Forum

Qt => Model-View (MV) => Тема начата: Alexandr Az от Февраль 20, 2011, 02:06



Название: Смущает beginInsertRows
Отправлено: Alexandr Az от Февраль 20, 2011, 02:06
Добавляем строки в модель
Код:
beginInsertRows(коли-во записей)
//загрузка данных
endInsertRows

В общем шаблонный случай. Если кол-во вставляемых записей нам не известно, определяем буфер до вызова beginInsertRows, закачиваем данные, а между beginInsertRows и endInsertRows копируем в модель. Это шаблон. Что же у нас?

Делаем ли мы так:
Код:
//загрузка данных
beginInsertRows(коли-во записей)
endInsertRows
или по правилам не имеет значение.

Т.е. я вообще не знаю зачем эта пара методов, кроме как посыла сигнала о том, что данные изменились.

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

А что же смущает..... !!!
Да исходники самой же Qt
Пример из fetchMore QSqlQuery:
Код:
q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row());
bottom = newBottom;
q->endInsertRows();
Где bottom  - указатель на последнюю строку, ну, можете считать её номер.

Т.е. сидел какой то троль, думал думал, думал думал.  Шо ж туда запихнуть? Не запихнуть нельзя - скажут дурак, два парных метода, если их сделали, значит нужно. И запихнул. И вроде логично как бы. Ну вот изменил кол-во строк в модели и можно считать это загрузкой данных...... Мало ли, может где ещё этот bottom по дороге участвует.... Вообщем так и осталось не понятным, зачем же они!



Название: Re: Смущает beginInsertRows
Отправлено: developer от Февраль 20, 2011, 05:49
Кстати, мне тоже интересно


Название: Re: Смущает beginInsertRows
Отправлено: lit-uriy от Февраль 20, 2011, 07:55
q->beginInsertRows(...) - сообщает о том, что данные собираются изменится
bottom = newBottom; - кол-во данных изменилось
q->endInsertRows(); - сообщает об изменении


Название: Re: Смущает beginInsertRows
Отправлено: Alexandr Az от Февраль 20, 2011, 10:05
q->beginInsertRows(...) - сообщает о том, что данные собираются изменится
bottom = newBottom; - кол-во данных изменилось
q->endInsertRows(); - сообщает об изменении

Это и так понятно из моего первого поста. Напишите вы bottom = newBottom перед beginInsertRows  или внутри, не имеет значение.
Вот в чём вопрос. И так, переписываем:
Код:
1. bottom = newBottom; - кол-во данных изменилось
2. q->beginInsertRows(...) - сообщает о том, что данные собираются изменится
3. q->endInsertRows(); - сообщает об изменении
Все работает и теоретически проблема может произойти только в случае, если между 1-й и 2-й строчкой кода произойдёт событие с моделью, что невозможно.

Такая парная конструкция обычно использовалась для GUI - мы вставляем записи, но не хотим чтобы перерисовка происходила после вставки каждой. Но в данном случае мне не понятно.


Название: Re: Смущает beginInsertRows
Отправлено: lit-uriy от Февраль 20, 2011, 10:25
>>или внутри, не имеет значение.
имеет, т.к. подключенные к модели объекты не будут ничего знать о предстоящем изменении


Название: Re: Смущает beginInsertRows
Отправлено: Alexandr Az от Февраль 20, 2011, 11:32
>>или внутри, не имеет значение.
имеет, т.к. подключенные к модели объекты не будут ничего знать о предстоящем изменении

Не важно, уже превращается в никому не нужную дискуссию. Вы не поняли сам вопрос. Концепция полностью понятна. Вы говорите очевидные вещи, разжёванные в самом вопросе.

Цитировать
имеет, т.к. подключенные к модели объекты не будут ничего знать о предстоящем изменении

Да и плевать что не знают. Узнают когда вызовем endInsertRows.

Приведу более практические размышления.
Реализовываем модель. К примеру пишем аналог QSqlQuery -  т.е. таблица. Между нашей пару методов изменяем кол-во строк.
Почему только кол-во строк? Есть несколько условий для данной модели, которые СИЛЬНО! упрощают реализацию:
1. Модель плоская (таблица).
2. Данные растут только вниз.

Что происходит: добавили данные, но модель об этом не знает. Увеличили кол-во строк - опа, модель узнала.
Если у нас дерево, да ещё и данные могут вставляться в различные уровни, такой простой вещью не обойтись, что меня не очень радует.

Если так не понятны мучения  - да работает всё и без этого. Если бы оно глючило или в документации было бы указано мне бы было проще. Да, судя по коду косяки могут быть, но только если модель в другом потоке.


Название: Re: Смущает beginInsertRows
Отправлено: lit-uriy от Февраль 20, 2011, 13:05
>>добавили данные, но модель об этом не знает. Увеличили кол-во строк - опа, модель узнала.
не понял.
Добавили данные куда?
почему кол-во строк (где-то) не зависит от кол-ва данных?


Название: Re: Смущает beginInsertRows
Отправлено: Alexandr Az от Февраль 20, 2011, 13:15
>>добавили данные, но модель об этом не знает. Увеличили кол-во строк - опа, модель узнала.
не понял.
Добавили данные куда?
почему кол-во строк (где-то) не зависит от кол-ва данных?

Извиняюсь, как то тяжело пишу.
Код:
Загружаем данные в модель. Она о них не знает, потому что они лежат за пределами bottom
q->beginInsertRows(...) - сообщает о том, что данные собираются изменится
bottom = newBottom; - кол-во данных изменилось  - т.е. сказали модели, что у нас новое кол-во строк
q->endInsertRows(); - сообщает об изменении



Название: Re: Смущает beginInsertRows
Отправлено: Akon от Февраль 20, 2011, 14:05
beginInsertRows()/endInsertRows() и beginRemoveRows()/endRemoveRows() - двухфазное оповещение об изменении, иногда необходимое.

Зачем это нужно? Допустим, в модели всего две строки, обе выделены (см. QItemSelectionModel). Далее добавляем новую строку в середину, т.е. выделенными должны быть исходные строки 1 и 3.

Теперь рассмотрим двух клиентов модели - 1-й уже упомянутый QItemSelectionModel, 2-й - тот, который использует помимо модели также и первого клиента, типичный пример - QAbstractItemView (см. QAbstractItemView::setModel(), QAbstractItemView::setSelectionModel()). Пусть будет только однофазное оповещение о добавлении строки по endInsertRows()  (сигнал rowsInserted()).

В этом случае возможно, что QAbstractItemView первым обработает сигнал и отрисует выделение на исходный строках 1 и 2 (а не 2 и 3!), т.к. QItemSelectionModel еще не обновилась (т.е. есть момент времени, в который клиент имеет некорректную информацию о выделенных строках!). Если же QItemSelectionModel обработает сигнал первой, то проблемы не будет. Т.о. вы всегда должны следить за порядком вызова слотов клиентов, что крайне непрактично (формально порядок вызова слотов вообще не определен!).

Чтобы исключить данную проблему используется две фазы (два сигнала). QItemSelectionModel использует первый сигнал (rowsAboutToBeInserted(), испускаемый beginInsertRows()) и всегда обновляется до любых зависящих от нее клиентов.