У меня есть следующие проблема:
когда я звоню update()
на QListView
, его paintEvent()
является не срабатывает, если над виджетом не происходит какое-либо другое событие (перемещение мыши, получение фокуса ….)
я использую Qt 4.8.3, и если это точно не ошибка в версии, я бы предпочел не обновляется (как показывает мой опыт, обновления приносят больше хлопот, чем пользы).
Вопрос:
Как сделать QListView
(а также Q...View
) обновить в следующий раз, когда основной цикл получит контроль?
Некоторый фон как то, что я решаю, если это поможет:
Имеется в виду однопоточное приложение.
Внизу есть некоторые независимый (нет Qt) модель, который является иерархическим, и потребители запрашивают подпункты. Элементы в нижней части иерархии могут быть изменены.
На модификации, запросы потребителей W (ritable) Пункт. В этот момент на детали модели влияют отчеты об изменениях. «модифицированный» через подход наблюдателя. Таким образом, наблюдатели уведомлены в начало изменений (модель возвращает доступный для записи объект, не имеет никакого контроля или идеи, когда изменение заканчивается).
Ожидается, что потребитель завершит модификацию, прежде чем вернуться из функции / метода, который начал модификацию.
Ожидается, что модифицирующие методы / функции будут вызываться из основного потока, поэтому в следующий раз, когда основной поток будет работать с графическим интерфейсом, модель будет в согласованном состоянии, и потребители смогут обновить ее.
QModel
Это делается для предоставления данных из модели ниже в доступном формате Qt.
Далее идут QWidget
s (списки / текстовые поля / метки) визуализация данных для пользователя,
они модифицированы для поддержки Desync()
метод, который помечает визуализированные данные как не синхронизированные и переопределяемые paintEvent
, который проверяет inSync
государство. Для простого QWidget
Подобно меткам, при синхронизации вызывается обратный вызов, который просто заполняет данные. За Q...View
Я предполагал заставить модели излучать modelReset
, поэтому список перезагружает количество строк и содержимое видимых.
На вершине класс собирает все это вместе в своем регионе, который подключен к наблюдателям, и о зарегистрированных изменениях Desync
соответствующие виджеты.
Все методы, изменяющие что-либо, подключаются через Qt Thieie сигнал / слот к кнопкам / комбинированным спискам / другим элементам графического интерфейса, так что я предполагаю, что все это работает под основным потоком.
Идея перемен:
Desync
) Соответствующий QWidget
как не синхронизированоQWidget
s помечены как несинхронизированные и запланированные для обновления, но не пытаются получить доступ к чему-либо, так как мы работаем в основном потоке* Что я заметил: *
update()
результаты в paintEvent
для большинства виджетов, у которых вообще нет модели (метка / текстовое поле …)update()
не приводит к paintEvent
за QListView
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
в следующий раз основной цикл получает управление (или даже несколько циклов позже).
Вы сделали это неправильно.
Не трогай QListView
тебе не нужно Просто исправьте модель данных (Qt), а остальные будут работать из коробки.
Ваша модель myModel
следует просто вызывать надлежащие методы при изменении данных. Эта модель должна соблюдать источник реальных данных.
Когда что-то случится с данными:
Если вы делаете это правильно, больше ничего не нужно.