我正在使用QML MapItemView
组件与基于C++ QAbstractListModel
的模型。 MapItemView
在模型重置时或者添加新项目或删除现有项目时正常工作。但是,MapItemView
未反映对已添加项目的更改。MapItemView在dataChanged信号后未更新
我已经第一次遇到这个问题了Qt 5.4,但我仍然面对它更新到Qt的5.5
后,下面的例子显示了2种不同型号的问题:基于QAbstractListModel
和QML ListModel
一个C++模型。 它可以切换从一个模型到另一个,按压右上方按钮:
- 当使用QML模型,点击在地图将添加新的元素和修改所述第一元件。
- C++模型使用
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++模型添加完整的代码。 –
我现在用一个完整的例子编辑我的问题。 –