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