未使用setContextProperty

时间:2019-06-15 21:10:45

标签: c++ qt model qml

我是Qt的新手,在将模型传递给View时遇到问题。 我的视图包含一堆按钮和一个带有一些标记的地图,这些标记的纬度/经度来自我的模型。 单击按钮将更新地图上的标记(删除一些标记和/或显示新标记)。

问题是:当我的模型(一个QList)在C ++方面得到更新时,QML却没有。

(我知道似乎已经有人问过这种问题,但是在阅读了不同的答案之后,我无法清楚地知道我是否可以摆脱使用更聪明的调用setContextProperty()的方式,或者是否可以必须使用诸如发出信号和绑定属性之类的东西,在阅读了一些文档之后,我也无法清楚地看到这一点)

架构如下:

  1. 具有QApplication实例化和MainWindow的主类(MainWindow是自定义QMainWindow类)。 App被执行,Window被显示。

  2. 具有updateMap()方法的Mapwidget类(自定义QQuickWidget类):

    • 对用户界面上的按钮单击做出反应
    • 更新模型(QList)
    • 使用setContextProperty()方法将更新的模型传递给 视图
  3. 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(),视图也看不到更新的模型?

谢谢您的帮助

1 个答案:

答案 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
            }
        }
    }
}

enter image description here

完整的示例是here