Обновление QListView - не вызывает обновление

У меня следующая проблема:

когда я звоню update() на QListView, его paintEvent() не срабатывает, если над виджетом не происходит какое-либо другое событие (перемещение мыши, получение фокуса....)

Я использую Qt 4.8.3, и, если это не является ошибкой в ​​версии, я бы предпочел не обновляться (так как из моего опыта обновления несут больше проблем, чем преимуществ).

Вопрос: как сделать QListView (а также Q...View) обновить в следующий раз, когда основной цикл получит контроль?

Некоторый фон как то, что я решаю, если это помогает:

Имеется в виду однопоточное приложение.

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

На модификацию потребительский запрос W (ritable) Item. В этот момент на части модели влияют отчеты об изменениях, "модифицированные" с помощью подхода наблюдателя. Таким образом, наблюдатели уведомляются в начале изменения (модель возвращает доступный для записи объект, не имеет никакого контроля или идеи, когда изменение заканчивается).

Ожидается, что потребитель завершит модификацию, прежде чем вернуться из функции / метода, который начал модификацию.

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

QModelЭто делается для предоставления данных из модели ниже в доступном формате Qt.

Далее идут QWidgets (списки / текстовые поля / метки) визуализируют данные для пользователя, они модифицированы для поддержки Desync() метод, который помечает визуализированные данные как не синхронизированные и переопределяемые paintEvent, который проверяет inSync государство. Для простого QWidgetПодобно меткам, при синхронизации вызывается обратный вызов, который просто заполняет данные. За Q...ViewЯ предполагал заставить модели излучать modelReset, поэтому список перезагружает количество строк и содержимое видимых.

На вершине класс собирает все это вместе в своем регионе, который подключен к наблюдателям, а также о зарегистрированных изменениях Desync соответствующие виджеты.

Все методы, изменяющие что-либо, подключаются через Qt Thieie сигнал / слот к кнопкам / комбинированным спискам / другим элементам графического интерфейса, поэтому я предполагаю, что все это работает под основным потоком.

Идея перемен:

  • Событие, вызванное GUI, основной поток начинает обработку метода изменения потребителя
  • потребитель получает необходимые предметы для сдачи
  • потребитель получает записываемые предметы
  • отчеты ореальных моделях, модифицированные для наблюдателей
  • отметканаблюдателей (Desync) Соответствующий QWidgetкак не синхронизировано
  • QWidgets помечены как несинхронизированные и запланированные для обновления, но не пытаются получить доступ к чему-либо, так как мы работаем в основном потоке
  • потребитель выполняет изменение, во время которого реальная модель может быть даже противоречивой
  • потребитель возвращает контроль над тем, что называется
  • основной цикл выполняет обновления, которые переопределяются для синхронизации виджетов

* Что я заметил: *

  • update() результаты в paintEvent для большинства виджетов, у которых вообще нет модели (метка / текстовое поле...)
  • update() не приводит к paintEvent за QListView
  • repaint() не помогает (была просто дикая попытка)
  • перемещение мыши над виджетом приводит к paintEvent, а также QWidget синхронизирует
  • пытаясь visible(false); update(); visible(true); перекрашивает сразу
    • это неправильно, так как QWidget синхронизируется до того, как потребитель выполнит изменение
  • переключение окон (т.е. визуальная студия) или обратно приводит к paintEvent будучи призванным

Упрощенные источники, где взять поведение:

myList.h

  #ifndef __myList_h__
  #define __myList_h__

  #include <qlistview.h>

  class myList : public QListView
  {
     bool inSync;
     void sync();

     protected:
        virtual void paintEvent(QPaintEvent * event) override;

     public:
        myList(QWidget * parent);
        void Desync();
        virtual ~myList();
  };

  #endif

myList.cpp

  #include "myList.h"
  #include "myModel.h"

  void myList::sync()
  {
     if (inSync)
        return;

     inSync = true; //< set early, to prevent loops
     ((myModel*)model())->ResetModel();
  }

  void myList::paintEvent(QPaintEvent * event)
  {
     sync();
     QListView::paintEvent(event);
  }

  myList::myList(QWidget * parent) : QListView(parent), inSync(false)
  {}

  void myList::Desync()
  {
     inSync = false;
     update();
  }

  myList::~myList()
  {}

myModel.h

  #ifndef __myModel_h__
  #define __myModel_h__

  #include <QAbstractListModel>

  class myModel : public QAbstractListModel
  {
     Q_OBJECT;

     int & externalComplexData;

     public:
        myModel(int & externalComplexData);

        virtual int rowCount(QModelIndex const & parent = QModelIndex()) const override;
        virtual QVariant data(QModelIndex const & index, int role) const override;

        void ResetModel();

        virtual ~myModel();

  };

  #endif

myModel.cpp

  #include "myModel.h"

  myModel::myModel(int & externalComplexData) : externalComplexData(externalComplexData)
  {}

  int myModel::rowCount(QModelIndex const & parent) const
  {
     return 1;
  }

  QVariant myModel::data(QModelIndex const & index, int role) const
  {
     if (role != Qt::DisplayRole)
        return QVariant();

     return QString::number(externalComplexData);
  }

  void myModel::ResetModel()
  {
     reset();
  }

  myModel::~myModel()
  {}

tmp.h

  #ifndef __Tmp_H__
  #define __Tmp_H__

  #include <QtGui/QMainWindow>
  #include "ui_tmp.h"

  class tmp : public QMainWindow
  {
      Q_OBJECT

     public:
         tmp(QWidget *parent = 0, Qt::WFlags flags = 0);
         ~tmp();

     private:
         Ui::tmpClass ui;

     private slots:
         void clicked();
  };

  #endif

tmp.cpp

  #include "tmp.h"
  #include "myModel.h"

  int localComplexData = 0;

  tmp::tmp(QWidget *parent, Qt::WFlags flags)
      : QMainWindow(parent, flags)
  {
     ui.setupUi(this);

     ui.lst->setModel(new myModel(localComplexData));
     connect(ui.btn, SIGNAL(clicked()), this, SLOT(clicked()));
  }

  void tmp::clicked()
  {
     ui.lst->Desync();
     ++localComplexData;
  }

  tmp::~tmp()
  {}

Поведение: при нажатии кнопки обновляется внешняя модель, но список не синхронизируется.

При наведении мыши на список, он синхронизируется.

Ожидаемое поведение: регистрация желания программиста update()и привести к paintEvent в следующий раз основной цикл получает управление (или даже несколько циклов позже).

1 ответ

Решение

Вы сделали это неправильно. Не трогай QListView тебе не нужно Просто исправьте модель данных (Qt), а остальные будут работать из коробки.

Ваша модель myModel следует просто вызывать надлежащие методы при изменении данных. Эта модель должна соблюдать источник реальных данных. Когда что-то случится с данными:

  • данные изменяются - испускают сигнал dataChanged
  • данные добавляются или удаляются вызовом beginInsertRows и endInsertRows или других соответствующих версий

Если вы делаете это правильно, больше ничего не нужно.

Другие вопросы по тегам