MapItemView 在 dataChanged 信号后未更新
Posted
技术标签:
【中文标题】MapItemView 在 dataChanged 信号后未更新【英文标题】:MapItemView is not updated after a dataChanged signal 【发布时间】:2015-07-21 10:04:02 【问题描述】:我正在使用 QML MapItemView
组件和基于 C++ QAbstractListModel
的模型。 MapItemView
在模型重置或添加新项目或删除现有项目时工作正常。但是,MapItemView
并未反映对已添加项目的更改。
我在 Qt 5.4 中第一次遇到这个问题,但在更新到 Qt 5.5 后我仍然遇到它
以下示例显示了 2 个不同模型的问题:基于 QAbstractListModel
的 C++ 模型和 QML ListModel
。
可以从一个模型切换到另一个模型,按下右上角的按钮:
QTimer
每秒修改其内容。
MapItemView
不显示模型更改,无论模型类型是什么。当从一种模型切换到另一种模型时,可以看到MapView
得到了更新。
我可能遗漏了一些非常明显的东西,但我不明白它是什么。提前感谢您的帮助。
main.cpp 代码:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "playermodel.h"
int main(int argc, char *argv[])
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
PlayerModel playerModel;
engine.rootContext()->setContextProperty("playerModel", &playerModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
C++ 模型头文件(playermodel.h):
#ifndef PLAYERMODEL_H
#define PLAYERMODEL_H
#include <QObject>
#include <QAbstractListModel>
#include <QGeoPositionInfoSource>
#include <QTimer>
#include <QDebug>
struct PlayerData
PlayerData()
PlayerData(int _Azimuth, double lat, double lng)
Azimuth = _Azimuth;
Latitude = lat;
Longitude = lng;
int Azimuth = -1;
double Latitude = 0.;
double Longitude = 0.;
QVariant getRole(int role) const;
enum Roles
RoleAzimuth = Qt::UserRole + 1,
RoleLatitude,
RoleLongitude
;
;
class PlayerModel : public QAbstractListModel
Q_OBJECT
public:
PlayerModel();
~PlayerModel();
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const;
Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
virtual bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex());
void resetModel();
void updateModel();
public slots:
void testUpdateModel();
protected:
QHash<int, QByteArray> roleNames() const;
private:
QTimer m_timer;
QVector< PlayerData> m_lstValues ;
;
#endif // PLAYERMODEL_H
C++ 模型 (playermodel.cpp)
#include "playermodel.h"
QVariant PlayerData::getRole(int role) const
switch (role)
case Roles::RoleAzimuth:
return Azimuth;
case Roles::RoleLatitude:
return Latitude;
case Roles::RoleLongitude:
return Longitude;
default:
return QVariant();
PlayerModel::PlayerModel()
resetModel();
connect(&m_timer, SIGNAL(timeout()), this, SLOT(testUpdateModel()));
m_timer.start(1000);
PlayerModel::~PlayerModel()
void PlayerModel::testUpdateModel()
updateModel();
int PlayerModel::rowCount(const QModelIndex & parent) const
Q_UNUSED(parent);
return m_lstValues.size();
QVariant PlayerModel::data( const QModelIndex & index, int role ) const
if ( (index.row() < 0) || (index.row() >= rowCount()) )
return QVariant();
return m_lstValues[ index.row()].getRole( role);
void PlayerModel::resetModel()
qDebug() << "Reset players model";
beginResetModel();
m_lstValues.clear();
//populate with dummy value
m_lstValues.push_back( PlayerData( 10, 47.1, -1.6 ));
m_lstValues.push_back( PlayerData( 20, 47.2, -1.6 ));
m_lstValues.push_back( PlayerData( 30, 47.1, -1.5 ));
m_lstValues.push_back( PlayerData( 40, 47.2, -1.5 ));
endResetModel();
void PlayerModel::updateModel()
qDebug() << "update players model upon timeout";
//change the Azimuth of every model items
int row = 0;
for (PlayerData player : m_lstValues)
setData( index(row), (player.Azimuth + 1) % 360, PlayerData::RoleAzimuth);
row++;
//qDebug() << "First element azimuth is now : " << data( index(0),PlayerData::RoleAzimuth).toInt() << "°";
bool PlayerModel::setData(const QModelIndex & index, const QVariant & value, int role)
if ( (index.row() < 0) || (index.row() >= rowCount()) ) return false;
PlayerData& player = m_lstValues[ index.row() ];
switch (role)
case PlayerData::RoleAzimuth:
player.Azimuth = value.toInt();
break;
case PlayerData::RoleLatitude:
player.Latitude = value.toDouble();
break;
case PlayerData::RoleLongitude:
player.Longitude = value.toDouble();
break;
emit dataChanged(index, index );//, QVector<int>( role));
return true;
bool PlayerModel::removeRows(int row, int count, const QModelIndex & parent)
Q_UNUSED(count);
Q_UNUSED(parent);
beginRemoveRows(QModelIndex(), row, row);
m_lstValues.remove( row);
endRemoveRows();
return true;
QHash<int, QByteArray> PlayerModel::roleNames() const
QHash<int, QByteArray> roles;
roles[PlayerData::Roles::RoleAzimuth] = "Azimuth";
roles[PlayerData::Roles::RoleLatitude] = "Latitude";
roles[PlayerData::Roles::RoleLongitude] = "Longitude";
return roles;
Qt::ItemFlags PlayerModel::flags(const QModelIndex &index) const
if (!index.isValid())
return 0;
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
最后是 QML 文件:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtLocation 5.3
import QtPositioning 5.0
Window
id:mainWnd
visible: true
width : 1024
height:768
property bool useQMLModel: true
Map
id: map
anchors.fill: parent
anchors.margins: 50
plugin: Plugin name:"osm";
center: QtPositioning.coordinate(47.1, -1.6)
zoomLevel: map.maximumZoomLevel
MapItemView
id:mapItemView
model: mainWnd.useQMLModel ? qmlModel : playerModel
delegate: MapQuickItem
//anchorPoint:
id:delegateMQI
rotation: model.Azimuth
sourceItem: Rectangle
id:defaultDelegate
width:32
height:32
radius:16
opacity: 0.6
rotation:Azimuth
color:"blue"
Text
text: Azimuth
anchors.centerIn : parent
coordinate: QtPositioning.coordinate(Latitude,Longitude)
MouseArea
anchors.fill: parent
enabled : useQMLModel
//preventStealing: true
propagateComposedEvents: true
onClicked:
//Modify an item
var newAzim = Math.random()*360;
qmlModel.setProperty(0, "Azimuth", newAzim);
//Check modification
console.log("Azim:" + qmlModel.get(0).Azimuth );
qmlModel.setProperty(0, "Color", "blue");
//add a new item
qmlModel.append("Latitude": 47.05 + Math.random() *0.2, "Longitude":-1.75 + Math.random() *0.3, "Azimuth":0, "Color":"red")
console.log("Nb item:" + qmlModel.count );
map.update();
map.fitViewportToMapItems();
mouse.accepted = false
Connections
target:mapItemView.model
onDataChanged:
if (useQMLModel)
console.log("dataChanged signal Azim:" + qmlModel.get(0).Azimuth );
else
console.log("dataChanged signal Azim:" + playerModel.data( topLeft, 0x0101) );
ListModel
id:qmlModel
ListElement
Latitude: 47.1
Longitude: -1.6
Azimuth: 10.0
Rectangle
anchors.top : parent.top
anchors.left : parent.left
width : 400
height : 300
radius: 10
color:"grey"
ListView
id:lstView
model:mapItemView.model
anchors.fill:parent
delegate: Text
width:parent.width
height:50
verticalAlignment: TextInput.AlignVCenter
fontSizeMode : Text.Fit
font.pixelSize: 42
minimumPixelSize: 5
text: "Latitude : " + Latitude + " - Longitude :" + Longitude + " - Azimuth : " + Azimuth
Rectangle
anchors.right : parent.right
anchors.top : parent.top
radius : 10
color : "red"
width : 200
height : 50
Text
anchors.centerIn: parent
text:"switch model"
MouseArea
anchors.fill: parent
onClicked:
mainWnd.useQMLModel = !mainWnd.useQMLModel;
【问题讨论】:
我们也需要为您的模型提供完整的代码。理想情况下,您应该将所有 C++ 代码放在一个main.cpp
文件中,并将其添加到此问题中。该代码应包含模型的完整代码,以及用于设置 QML、模型和运行应用程序的 main()
。
感谢您的回复。实际上,我想用尽可能少的代码来展示这个问题,这就是我使用 QML 模型而不是我的 C++ 模型的原因,因为我对 QML 模型有同样的问题:我们可以看到模型在按下时发生了变化鼠标(也可以使用 Connection 元素来演示已发送 dataChanged 信号)。无论如何,我在新评论中添加了使用 C++ 模型的完整代码。
我现在用一个完整的例子来编辑我的问题。
我已经在错误报告中报告了这个问题:bugreports.qt.io/browse/QTBUG-47366
【参考方案1】:
以防万一有人面对帖子作者报告的相同issue,问题在Qt 5.6.0中得到解决
请注意,这已由已合并到 5.6 分支中的变更集 Ib92252d18c2229bc6d43e11362b8f13cdb48f315 (https://codereview.qt-project.org/#/c/123660/) 修复
【讨论】:
以上是关于MapItemView 在 dataChanged 信号后未更新的主要内容,如果未能解决你的问题,请参考以下文章