QListView 更新 - 不触发更新

QListView update - does not trigger update

我有以下问题:

当我在 QListView 上调用 update() 时,它的 paintEvent() 不会被触发 除非在小部件上发生其他事件(鼠标移动, 获得焦点....)

我正在使用 Qt 4.8.3,除非这肯定是版本中的错误,否则我宁愿不升级(因为根据我的经验,升级带来的麻烦多于好处。

问题: 如何使QListView(和Q...View)在下次主循环获得控制权时更新?

一些背景知识 如有帮助,我正在解决:

意味着单线程应用程序。

最下面是一些independent(没有Qt)model,是有层次的,消费者请求子项。层次结构底部的项目可能会被修改。

修改后,消费者请求 W(ritable)Item。在这一点上,模型部件通过观察者方法 "modified" 受到变更报告的影响 。所以观察者在变化开始时得到通知(模型returns可写对象,在变化结束时没有控制或想法)。

消费者应该在从开始修改的 function/method 返回之前完成修改。

修改 methods/functions 预计会从主线程调用,因此下次主线程修补 GUI 时,模型处于一致状态,消费者可以刷新。

QModel已完成以 Qt 可访问格式提供来自以下模型的数据。

接下来是 QWidgets (lists/textboxes/labels) 向用户可视化数据, 这些被修改以支持 Desync() 方法,该方法将可视化数据标记为不同步,并覆盖 paintEvent,检查 inSync 状态。对于像标签这样的简单 QWidgets,在同步时,回调被调用,它只是填充数据。对于 Q...View,我假定强制模型发出 modelReset,因此列表会重新加载行数和可见行的内容。

顶部是 class 将其全部收集在其区域下,与观察者挂钩,并根据报告的变化 Desync 相关小部件。

所有更改任何内容的方法都通过 signal/slot Qt thingie 连接到 buttons/comboboxes/other GUI 元素,因此我假设所有 运行 都在主线程下。

修改思路:

* 我观察到的:*

获得行为的简化来源:

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(甚至稍后的几个循环)。

你做错了。 不要触摸 QListView 你不必。只需修复数据模型 (Qt),其余的将开箱即用。

您的模型 myModel 应该在数据发生变化时简单地调用适当的方法。该模型应观察真实数据的来源。 数据何时会发生变化:

如果你正确地做到了这一点,就不需要其他任何东西了。