![](/img/trans.png)
[英]QAbstractListModel dataChanged signal not updating ListView (QML)
[英]C++/QML: ListView is not updated on dataChanged signal from QAbstractListModel
我正在嘗試為大型動態C / Fortran仿真編寫QML Gui。 我想要顯示的數據存儲在Fortran Common塊中,並按固定時間步驟更新。 我的問題是,當每個時間步之后發出dataChanged信號時,QML ListView不刷新,盡管Gui接收到信號(測試在下面的代碼中)。
我可能錯過了一些非常明顯的東西,因為當我向下輕彈我的ListView時,顯示的數據會更新並且正確(我猜是因為當QML引擎“看不見”並再次返回時重新呈現元素) 。 所以唯一不起作用的是每次收到dataChanged信號時ListView都會更新,而不僅僅是在重新渲染時。 以下是我的方法和相關代碼部分的更詳細說明。
每個模擬實體都有幾個屬性(alive,position ...),因此我決定為每個實體創建一個包含DataObject的ListModel。 這是相應的頭文件(實際模擬數據在“interface.h”中聲明為extern結構,因此我可以通過指針訪問它):
“acdata.h”
#include <QtCore>
#include <QObject>
#include <QtGui>
extern "C" {
#include "interface.h"
}
class AcDataObject : public QObject
{
Q_OBJECT
public:
explicit AcDataObject(int id_, int *pac_live, double *pac_pos_x, QObject *parent = 0) :
QObject(parent)
{
entity_id = id_;
ac_live = pac_live;
ac_pos_x = pac_pos_x;
}
int entity_id;
int *ac_live;
double *ac_pos_x;
};
class AcDataModel : public QAbstractListModel
{
Q_OBJECT
public:
enum RoleNames {
IdRole = Qt::UserRole,
LiveRole = Qt::UserRole + 1,
PosXRole = Qt::UserRole + 2
};
explicit AcDataModel(QObject *parent = 0);
virtual int rowCount(const QModelIndex &parent) const;
virtual QVariant data(const QModelIndex &index, int role) const;
Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
void do_update();
protected:
virtual QHash<int, QByteArray> roleNames() const;
private:
QList<AcDataObject*> data_list;
QHash<int, QByteArray> m_roleNames;
QModelIndex start_index;
QModelIndex end_index;
signals:
void dataChanged(const QModelIndex &start_index, const QModelIndex &end_index);
};
與標題一樣,.cpp文件也可以在Qt5 Cadaques Book中找到 ,除了我的構造函數遍歷所有模擬實體以設置指針。 此外,還有do_update函數,它為整個列表發出dataChanged信號。
“acdata.cpp”
#include "acdata.h"
AcDataModel::AcDataModel(QObject *parent) :
QAbstractListModel(parent)
{
m_roleNames[IdRole] = "entity_id";
m_roleNames[LiveRole] = "ac_live";
m_roleNames[PosXRole] = "ac_pos_x";
for (int i = 0; i < MAX_ENTITIES; i++) // MAX_ENTITIES is defined in interface.h
{
AcDataObject *data_object = new AcDataObject( i,
&fdata_ac_.ac_live[i], // fdata_ac_ is the C struct/Fortran common block defined in interface.h
&fdata_ac_.ac_pos_x[i] );
data_list.append(data_object);
}
}
int AcDataModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return data_list.count();
}
QVariant AcDataModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
if(row < 0 || row >= data_list.count()) {
return QVariant();
}
const AcDataObject *data_object = data_list.at(row);
switch(role) {
case IdRole: return data_object->entity_id;
case LiveRole: return *(data_object->ac_live);
case PosXRole: return *(data_object->ac_pos_x);
}
return QVariant();
}
QHash<int, QByteArray> AcDataModel::roleNames() const
{
return m_roleNames;
}
void AcDataModel::do_update() {
start_index = createIndex(0, 0);
end_index = createIndex((data_list.count() - 1), 0);
dataChanged(start_index, end_index);
}
Qt::ItemFlags AcDataModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) {return 0;}
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}
模擬運行時,每秒調用do_update()。 我用ListView創建了一個測試Gui,並將我的模型暴露給它:
摘錄自“threadcontrol.cpp”
acdata = new AcDataModel();
viewer = new QtQuick2ApplicationViewer();
viewer->rootContext()->setContextProperty("acdata", acdata);
viewer->setMainQmlFile(QStringLiteral("../lib/qml_gui/main.qml"));
viewer->showExpanded();
(此代碼是控制不同線程的較大文件的一部分。我非常確定其余部分與實際問題無關,這個問題變得非常長......)
所以最后有main.qml。 它包含一個包含MAX_ENTITIES元素的列表,每個元素都包含文本字段以顯示我的數據。 我還添加了一個Connections元素來檢查Gui是否收到了dataChanged信號。
“main.qml”
ListView {
id: listviewer
model: acdata
delegate: Rectangle {
/* ... some formatting stuff like height etc ... */
Row {
anchors.fill: parent
Text {
/* ... formatting stuff ... */
text: model.entity_id
}
Text {
/* ... formatting stuff ... */
text: model.ac_live
}
Text {
/* ... formatting stuff ... */
text: model.ac_pos_x
}
}
}
Connections {
target: listviewer.model // EDIT: I drew the wrong conclusions here, see text below!
onDataChanged: {
console.log("DataChanged received")
}
}
}
運行模擬時,每秒打印一次“DataChanged received”消息。
編輯:我連接到ListModel而不是這里的ListView,雖然ListView必須接收dataChanged信號。 由於連接到listviewer時控制台日志不起作用,我可能錯過了listView和dataChanged信號之間的連接。 但是,我認為這應該在實現dataChanged信號時自動工作?
附加信息:我在 Qt Map中發現了類似的問題 ,它實際上似乎是在Qt 5.6中修復的錯誤。 但是,使用Qt 5.7運行qmake並沒有解決我的問題。
您不能在類中聲明dataChanged()
信號,因為您要發出信號AbstractItemModel::dataChanged()
。 如果你重新聲明它,你添加一個新的和不同的信號,在任何地方都沒有連接。 如果刪除acdata.h中的聲明,一切都應該正常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.