我是Qt的新手,在将模型传递给View时遇到问题。 我的视图包含一堆按钮和一个带有一些标记的地图,这些标记的纬度/经度来自我的模型。 单击按钮将更新地图上的标记(删除一些标记和/或显示新标记)。
问题是:当我的模型(一个QList)在C ++方面得到更新时,QML却没有。
(我知道似乎已经有人问过这种问题,但是在阅读了不同的答案之后,我无法清楚地知道我是否可以摆脱使用更聪明的调用setContextProperty()的方式,或者是否可以必须使用诸如发出信号和绑定属性之类的东西,在阅读了一些文档之后,我也无法清楚地看到这一点)
架构如下:
具有QApplication实例化和MainWindow的主类(MainWindow是自定义QMainWindow类)。 App被执行,Window被显示。
具有updateMap()方法的Mapwidget类(自定义QQuickWidget类):
MainWindow类具有Mapwidget属性
到目前为止我尝试过的事情:
在调用setSource()方法之前在Mapwidget构造函数中调用setContextProperty()时,将考虑模型。因此,我用于将模型传递到视图中的语法应该是正确的。问题似乎在于此后对setContextProperty()的任何调用(在这种情况下:在updateMap()方法中)都没有传递给QML文件。
在不同级别(Mapwidget类,MainWindow类)调用setContextProperty(),结果是相同的,在应用程序首次启动后再也不会考虑。
我已经测试了模型,并知道它确实在updateMap()方法中进行了更新,这似乎是未将更新转移到QML文件中。
QML文件:
Item {
width: 1200
height: 1000
visible: true
Plugin {
id: osmPlugin
name: "osm"
}
Map {
id: map
anchors.fill: parent
plugin: osmPlugin
center: QtPositioning.coordinate(45.782074, 4.871263)
zoomLevel: 5
MapItemView {
model : myModel
delegate: MapQuickItem {
coordinate:QtPositioning.coordinate(
model.modelData.lat,model.modelData.lon)
sourceItem: Image {
id:image_1
source: <picturePath>
}
anchorPoint.x: image_1.width / 2
anchorPoint.y: image_1.height / 2
}
}
}
Mapwidget类:
mapwidget::mapwidget(QWidget *parent) : QQuickWidget(parent)
{
this->setSource(QUrl(QStringLiteral("qrc:/main.qml")));
}
void mapwidget::updateMap(QList<QObject *> &data)
{
/**
DO OPERATIONS TO UPDATE data
Each append has the following form :
data.append(new DataObject(someLatitude, someLongitude))
*/
this->rootContext()->setContextProperty("myModel", QVariant::fromValue(data));
}
在updateMap()方法中,附加到列表的QObject是自定义类DataObject的:
class DataObject : public QObject
{
Q_OBJECT
Q_PROPERTY(double lat READ lat WRITE setLat)
Q_PROPERTY(double lon READ lon WRITE setLon)
public:
explicit DataObject(QObject *parent = nullptr);
DataObject(double latitude, double longitude, QObject *parent =
nullptr);
void setLat(double latitude);
void setLon(double longitude);
double lat() const;
double lon() const;
double d_lat;
double d_lon;
}
为什么即使调用setContextProperty(),视图也看不到更新的模型?
谢谢您的帮助
答案 0 :(得分:0)
通过setContextProperty(...)
传递给您的名称是您传递的对象的别名,在绑定model: myModel
的情况下,它是在对象之间进行的,如果您传递的是具有相同别名的新对象不再是初始绑定,因为它们是不同的对象,它类似于:
T *t = new T;
connect(t, &T::foo_signal, obj, &U::foo_slot);
t = new T;
尽管两个对象都具有相同的别名(t
),但这并不意味着该连接与第二个对象保持不变。
解决方案是使用通知QML更新的对象,在这种情况下,解决方案是实现自定义QAbstractListModel:
CoordinateModel类
// coordinatemodel.h
#ifndef COORDINATEMODEL_H
#define COORDINATEMODEL_H
#include <QAbstractListModel>
#include <QGeoCoordinate>
class CoordinateModel : public QAbstractListModel
{
Q_OBJECT
public:
enum{
PositionRole = Qt::UserRole + 1000
};
explicit CoordinateModel(QObject *parent = nullptr);
void insert(int index, const QGeoCoordinate & coordinate);
void append(const QGeoCoordinate & coordinate);
void clear();
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
private:
QList<QGeoCoordinate> m_coordinates;
};
#endif // COORDINATEMODEL_H
// coordinatemodel.cpp
#include "coordinatemodel.h"
CoordinateModel::CoordinateModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void CoordinateModel::insert(int index, const QGeoCoordinate &coordinate){
int i = index;
if(index < 0) // prepend
i = 0;
else if (index >= rowCount()) // append
i = rowCount();
beginInsertRows(QModelIndex(), i, i);
m_coordinates.insert(i, coordinate);
endInsertRows();
}
void CoordinateModel::append(const QGeoCoordinate &coordinate){
insert(rowCount(), coordinate);
}
void CoordinateModel::clear(){
beginResetModel();
m_coordinates.clear();
endResetModel();
}
int CoordinateModel::rowCount(const QModelIndex &parent) const{
if (parent.isValid())
return 0;
return m_coordinates.count();
}
QVariant CoordinateModel::data(const QModelIndex &index, int role) const{
if (index.row() < 0 || index.row() >= m_coordinates.count())
return QVariant();
if (!index.isValid())
return QVariant();
const QGeoCoordinate &coordinate = m_coordinates[index.row()];
if(role == PositionRole)
return QVariant::fromValue(coordinate);
return QVariant();
}
QHash<int, QByteArray> CoordinateModel::roleNames() const{
QHash<int, QByteArray> roles;
roles[PositionRole] = "position";
return roles;
}
MapWidget类
// mapwidget.h
#ifndef MAPWIDGET_H
#define MAPWIDGET_H
#include <QQuickWidget>
class CoordinateModel;
class MapWidget : public QQuickWidget
{
public:
MapWidget(QWidget *parent=nullptr);
CoordinateModel *model() const;
private:
CoordinateModel *m_model;
};
#endif // MAPWIDGET_H
// mapwidget.cpp
#include "coordinatemodel.h"
#include "mapwidget.h"
#include <QQmlContext>
MapWidget::MapWidget(QWidget *parent):
QQuickWidget(parent),
m_model(new CoordinateModel{this})
{
rootContext()->setContextProperty("myModel", m_model);
setSource(QUrl(QStringLiteral("qrc:/main.qml")));
}
CoordinateModel *MapWidget::model() const
{
return m_model;
}
然后您可以将其用作:
MapWidget w;
w.model()->append(QGeoCoordinate(45.782074, -6.871263));
w.model()->append(QGeoCoordinate(50.782074, -1.871263));
w.model()->append(QGeoCoordinate(55.782074, 4.871263));
w.model()->append(QGeoCoordinate(45.782074, 4.871263));
w.model()->append(QGeoCoordinate(50.782074, 4.871263));
w.model()->append(QGeoCoordinate(55.782074, 4.871263));
main.qml
import QtQuick 2.12
import QtLocation 5.12
import QtPositioning 5.12
Item {
width: 1200
height: 1000
visible: true
Plugin {
id: osmPlugin
name: "osm"
}
Map {
id: map
anchors.fill: parent
plugin: osmPlugin
center: QtPositioning.coordinate(45.782074, 4.871263)
zoomLevel: 5
MapItemView {
model : myModel
delegate: MapQuickItem {
coordinate: model.position
sourceItem: Image {
id: image_1
source: "http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_red.png"
}
anchorPoint.x: image_1.width / 2
anchorPoint.y: image_1.height / 2
}
}
}
}
完整的示例是here。