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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: QListView и его модель - не показываются новые записи после добавления в модель.  (Прочитано 15642 раз)
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« : Июль 20, 2008, 00:37 »

Здравствуйте!


Столкнулся с такой проблемой. Имею приложение из одного окна, на котором расположены виджеты QTreeView и QListView. При клике на определенную ветку дерева в QTreeView, у меня появляется нужный список в QListView. Делается это так

Код:
// Действия при клике на ветку дерева
void mainwindow::on_nodetreeview_clicked(const QModelIndex &index)
{
 // Получаем нужную модель
 TreeItem *item = nodemodel->getItem(index);
 QAbstractListModel *tabmod = item->recordtable_getmodel();
 
 // Загрузка модели в представление
 recordview->setModel(tabmod);
}

И после этого, все пункты списка, которые есть в модели, видны на экране в виджете QListView.

Теперь мне нужно сделать функцию добавления пункта в список QListView. Я ее сделал в виде слота, который вызывается при клике на соответствущий пункт контекстного меню. Данный код расположен в том же файле главного окна что и предыдущий.

Код:
// Слот добавления новой записи в таблицу коннечых записей
void mainwindow::recordview_add_new(void)
{
 // Получение ссылки на модель таблицы конечных записей
 recordtablemodel *model=(recordtablemodel *)recordview->model();

 // Вставка данных в модель
 model->insert_new_record("New record in table","Text of new record");
 
 recordview->setModel(model);
 recordview->update();
 recordview->repaint();
}

Вставка данных проходит нормально, и модель начинает содержать новый пункт. Но вид этот пункт не отображает, видны только старые записи. Не помогает ни вставка этой же модели как "новой" через recordview->setModel(model);, ни update, ни repaint. А вот если кликнуть на какую-нибудь другую ветку, а затем вернуться в ту ветку, где было сделано добавление пункта, то этот новый пункт будет виден в списке.

Вопрос - как правильно обновить вид QListView, чтобы он начал показывать новые добавленные пункты?
 
Записан

Собираю информацию по крупицам
http://webhamster.ru
ритт
Гость
« Ответ #1 : Июль 20, 2008, 02:25 »

 recordview->update();
 recordview->repaint();
выбрось сразу

если recordview->model() == model, обычно ничего произойти не должно

что делает insert_new_record(...) ?

советую почитать документацию по модель-представление! при добавлении данных в модель _не нужно_ обновлять представление, т.к. модель _обязана_ сигнализировать об изменении данных.
поскольку не имею представления что делает insert_new_record(...), могу лишь догадываться, что добавление строки производится неверно...
Записан
Hort
Гость
« Ответ #2 : Июль 20, 2008, 08:59 »

попробуй с QTreeView использовать reset()

советую почитать документацию по модель-представление! при добавлении данных в модель _не нужно_ обновлять представление, т.к. модель _обязана_ сигнализировать об изменении данных.
поскольку не имею представления что делает insert_new_record(...), могу лишь догадываться, что добавление строки производится неверно...
у меня напр модель имеет отличную от стандартной структуру. реализовал только методы отображения и модель у меня для QTreeView - ридонли. добаляю данные туда не стандартным интерфейсом, а своим собственным, подстроенным под особенности моей модели. и у меня была тоже такая проблемма. только что смотрел пример itemviews/editabletreemodel там вроде никаких специальных сигналов не высылается, и само представление не обновляется. может у меня не работает из-за того, что интерфейс добаления данных не стандартный? писал строго на основании примера itemviews/simpletreemodel в котором представленна модель только для чтения
« Последнее редактирование: Июль 20, 2008, 09:21 от Hort » Записан
ритт
Гость
« Ответ #3 : Июль 20, 2008, 11:03 »

на самом деле там всё очень просто...нужно лишь некоторые правила неукоснительно соблюдать
ака, добавил строку - изволь позвать бэгинИнсертРовз+эндИнсертРовз; модифицировал данные - изволь сигнализировать датаЧенджед; и т.п. - обо всём подробно расписано в документации по модель-представление и по абстратным моделям/представлениям...
и абсолютно не имеет значения для каких целей проектировалась модель - только для чтения или для чтения/изменения данных с политиками записи (склтаблмодели).
если же оно всё-равно отказывается работать и видимых причин на то нет, используйте стандардайтеммодель - там добрые дяди уже всё написали...правда, в ущерб произодительности
Записан
Hort
Гость
« Ответ #4 : Июль 20, 2008, 11:36 »

на самом деле там всё очень просто...нужно лишь некоторые правила неукоснительно соблюдать
ака, добавил строку - изволь позвать бэгинИнсертРовз+эндИнсертРовз; модифицировал данные - изволь сигнализировать датаЧенджед; и т.п. - обо всём подробно расписано в документации по модель-представление и по абстратным моделям/представлениям...
и абсолютно не имеет значения для каких целей проектировалась модель - только для чтения или для чтения/изменения данных с политиками записи (склтаблмодели).
если же оно всё-равно отказывается работать и видимых причин на то нет, используйте стандардайтеммодель - там добрые дяди уже всё написали...правда, в ущерб произодительности
у меня корректно не удалялись данные. добавил бегинДелитРовз и эндДелитРовз - помню я с ними намучался - т.к. у меня при изменении модели не передается индекс модели, а просто число. пришлось исправлять всетаки на индекс модели. а так вставлять мне проще именно через числовой индекс и обновить модель. а насчет "сигнализировать датаЧенджед" я в примере вообще не видел никаких высыланий сигналов (itemviews/editabletreemodel)! как тогда там это происходит?
Записан
ритт
Гость
« Ответ #5 : Июль 20, 2008, 13:05 »

в itemviews/editabletreemodel логика модели заточена под примитивный пример - показать как можно организовать свой механизм вставки/удаления строк/детей. но я бы сказал, что пример не доведён до ума, т.к. сбивает новичков с толку
когда добавляется айтем (строка) - после отработки endInsertRows обновляются данные сразу для всей строки
НО
попробуй кликнуть на "добавить строку" - после курсора появится новая строка, которая...правильно - пустая. и пока не произведёшь событие, требующее прочесть данные (метод data любой модели), строка останется пустая.
если бы пример был морально завершённым, в перегруженном treemodel.cpp:setData(...) была бы строчка типа emit dataChanged(...), а юзверю не пришлось бы передёргивать мышой по вьюхе чтобы обновить данные.
тот факт, что заглядываешь в сорцы, - это хорошо. но мир не идеален - стоило бы и теорию укрепить.

итого: ещё раз настоятельно советую _внимательно_ читать документацию и посетить ветку "Книги по QT" (http://prog.org.ru/forum/index.php/topic,765.0.html), если ещё не посещал(и)...
Записан
Hort
Гость
« Ответ #6 : Июль 20, 2008, 14:17 »

спасибо за развернуты ответ! подтяну теорию. Из книг - читаю Макса Шлее. книга нравится, но только для общего ознакомления и понимания Qt, все равно без Assistent не обойдешся =)
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #7 : Июль 20, 2008, 14:22 »

Спасибо за ответы. У меня действительно как и у товарища Horta самодельная модель, и я не совсем понимаю как генерировать сигнал, что данные изменились, с нужными индексами модели.

Точнее, проблема в вычислении индексов модели, непойму как делать надо.

Вот код метода модели, о котором спрашивал Константин. Я его доработал чтоб он эмитил сигнал, но вид всеравно не обновляется.

В заголовке у класса recordtablemodel есть такие определения

Код:
    typedef QMap<QString, QString> reclintype; // Тип для одной строки таблицы
    QList< reclintype > table; // Сама таблица

А вот реализация добавления новой записи

Код:
// Добавление в конец списка новой записи
void recordtablemodel::insert_new_record(QString name, QString text)
{
  // Создается и заполняется объект одной записи
  reclintype tmpline;
  tmpline["name"]=name;
  tmpline["text"]=text;
     
  // Данная запись размещается в таблице записей, которую хранит модель
  table << tmpline;
 
  // Вычисление индекса новой добавленой строки
  QModelIndex index=this->index(table.size(),1);
  if(index.isValid())
   emit dataChanged(index,index); // Посылается сигнал что данные были изменены
  else
   qDebug() << "Error calculate index in recordtablemodel"; 
}


Не понял правда, как идет нумерация строк и колонок, с нуля или с единицы. Но если использовать конструкцию index(table.size(),1) - то получаем ошибку Error calculate index in recordtablemodel. А если использовать index(table.size()-1,0), то ошибки не возникает, но новая строка не появляется...

Меня вообще беспокоит конструкция

Код:
  QModelIndex index=this->index(x,y);

Вроде как она вызывается после добавления строки в table. Метод data(), например, возвращает строку ["name"] для данного индекса после "перещелкивания" вида. (Строка ["name"] и есть текст строки, отображаемый в QViewList). Вроде как, данная конструкция правильно высчитывает индекс. Но он по каким-то причинам получается невалидным. Непойму почему.
Записан

Собираю информацию по крупицам
http://webhamster.ru
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #8 : Июль 20, 2008, 14:42 »

Еще момент - поставил дебаг вывод (и выяснил что нумерация начинается с нуля). Теперь код эмита сигнала выглядит так

Код:
  QModelIndex index=this->index(table.size()-1,0,QModelIndex());
  qDebug() << this->data(index,Qt::DisplayRole);
  if(index.isValid())
  {
    qDebug() << "Emit dataChanged()";
    emit dataChanged(index,index); // Посылается сигнал что данные были изменены
  }
  else
   qDebug() << "Error calculate index in recordtablemodel";


В ответ получаю

Код:
QVariant(QString, "New record in table")
Emit dataChanged()

то есть индекс модели для новой добавленой строки вычисляется правильно. Но почему тогда эмит сигнала не обновляет вид, и новой строки не видно?
Записан

Собираю информацию по крупицам
http://webhamster.ru
ритт
Гость
« Ответ #9 : Июль 20, 2008, 15:02 »

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

в общем, кратко...
Код:
// Добавление в конец списка новой записи
void recordtablemodel::insert_new_record(QString name, QString text)
{
  /* говорим, что приспичило нам вставить строку(и), к чему и приступили
  * если так сделаем, вьюха успеет подготовить свои ресурсы, но не будет пытаться получить данные этой строки, т.к. строка ещё в зародыше и не готова выйти в Мир */
  beginInsertRows(QModelIndex(), table.size(), table.size() + 1);

  // Создается и заполняется объект одной записи
  reclintype tmpline;
  tmpline["name"]=name;
  tmpline["text"]=text;
      
  // Данная запись размещается в таблице записей, которую хранит модель
  table << tmpline;

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

  // а теперь орём "огонь!"
  endInsertRows();
  /* в этом месте вьюха уже в обычном режиме отобразила юзверю новорожденную строку. причём, не с перепугу, когда юзверь кликнул "где-то-там", а вьюха переспросила количество строк и внезапно узнала, что у неё добавилось ртов. */

  // счастливый конец истории.
  delete this; // можно помирать :)
}
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #10 : Июль 20, 2008, 15:22 »

Во, заработало через beginInsertRows()...endInsertRows(). А я то думал что dataChanged() можно использовать при добавлении данных. Ну типа строки небыло, потом она появилась, значит произошло изменение и его надо показать...

А вот вопрос по последней строчке "delete this;". Это для чего надо? Зачем удалять текущий объект, как дальше тогда работать? Или это йумар такой?
Записан

Собираю информацию по крупицам
http://webhamster.ru
ритт
Гость
« Ответ #11 : Июль 20, 2008, 15:52 »

йумар
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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