如何在QML

时间:2017-11-20 11:00:00

标签: c++ qt maps qml coordinates

我想用Qt / QML在地图上显示大量的点。这些点在.txt文件中详细说明。

我正在寻找使用的过程但不幸的是,我只通过插件找到一个查询方法来显示来自服务器的地方(osm,google ...)。我不能使用它,这些要点非常具体。

实现此任务的最佳方法是什么?

另外,除了“osm插件”之外,还需要使用“plugin itemsoverlay”来显示特定图层上的这些点吗?

感谢您的帮助。

好的,现在回到代码的战斗中。

这是主要的.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QObject>
#include <QGeoCoordinate>
#include <QDebug>

class NavaidsPoint: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QGeoCoordinate position READ position WRITE setPosition NOTIFY positionChanged)

public:
    NavaidsPoint(QString code, double latitude, double longitude, QString country = "")
    {
        m_code = code;
        m_latitude = latitude;
        m_longitude = longitude;
        m_country = country;
        m_position.setLatitude(latitude);
        m_position.setLongitude(longitude);
    }

    void setPosition(const QGeoCoordinate &c) { //Affectation des nouvelles coordonnées de position
        if (m_position == c)
            return;

        m_position = c;
        emit positionChanged(); //Emission du signal de changement de position
    }

    QGeoCoordinate position() const
    {
        return m_position; //Lecture des coordonnées de position
    }

    Q_INVOKABLE QString oaciCode() const {
        return m_code;
    }

    Q_INVOKABLE QString countryCode() const {
        return m_country;
    }

signals:
    void positionChanged();

private:
    QGeoCoordinate m_position;
    double m_latitude;
    double m_longitude;
    double m_altitude;
    QString m_code;
    QString m_country;
};




int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    NavaidsPoint oslo("Oslo", 59.9154, 10.7425, "NG");

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("oslo", &oslo);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

#include "main.moc"

和main.qml

import QtQuick 2.6
import QtQuick.Window 2.2
import QtPositioning 5.5
import QtLocation 5.6

Window {
    width: 700
    height: 500
    visible: true
    title: qsTr("Test implantation coordonnées")

    property variant topLeftEurope: QtPositioning.coordinate(60.5, 0.0)
    property variant bottomRightEurope: QtPositioning.coordinate(51.0, 14.0)
    property variant viewOfEurope:
            QtPositioning.rectangle(topLeftEurope, bottomRightEurope)

    Map {
        id: mapOfEurope
        anchors.centerIn: parent;
        anchors.fill: parent
        plugin: Plugin {
            name: "osm"
        }

        MapCircle {
            center: oslo.position
            radius: 5000.0
            color: 'green'
            border.width: 3
            MouseArea {
                anchors.fill: parent
                onDoubleClicked: {
                    console.log("Doubleclick on " + oslo.oaciCode())
                }
                onClicked: {
                    console.log("Point : " + oslo.oaciCode() + " " + oslo.position + " " + oslo.countryCode())
                }
            }
        }
    visibleRegion: viewOfEurope
    }
}

奥斯陆这个独特的观点一切正常。现在我需要放置数千点。这种结构不能像那样工作,因为我需要为它们中的每一个实现一个NavaidsPoint,并为它们中的每个实现setContextProperty。同样,在main.QML中,圆圈与对象绑定:

center : oslo.position

此外,我还有oaciCode和countryCode。因此,这部分代码必须是通用的,而不是特定于单个对象。

那么,什么是解决这个问题的最佳方法呢?

我希望能够在这些精确的范围内进入SO范围。

再次感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

如果要加载许多元素,一个好的选择是使用MapItemView,这需要一个提供数据的模型,并指出适当的委托。

模型是基于QAbstractListModel创建的,我们将使用角色将属性公开给QML,因为它创建的类不一定要从QObject继承,在这种情况下,它将是以下。

#ifndef NAVAIDSPOINT_H
#define NAVAIDSPOINT_H

#include <QGeoCoordinate>
#include <QString>

class NavaidsPoint
{
public:
    NavaidsPoint(QString code, double latitude, double longitude, QString country = ""){
        m_code = code;
        m_country = country;
        m_position.setLatitude(latitude);
        m_position.setLongitude(longitude);
        m_position.setAltitude(0.0);
    }

    void setPosition(const QGeoCoordinate &c) { //Affectation des nouvelles coordonnées de position
        m_position = c;
    }

    QGeoCoordinate position() const{
        return m_position; //Lecture des coordonnées de position
    }

    QString oaciCode() const {
        return m_code;
    }

    QString countryCode() const {
        return m_country;
    }

private:
    QGeoCoordinate m_position;
    QString m_code;
    QString m_country;
};


#endif // NAVAIDSPOINT_H

QAbstractListModel要求您实施方法rowCountdataroleNames,同时我已经实现了add方法,您必须通知模型更改,示例如下

#ifndef NAVAIDSMODEL_H
#define NAVAIDSMODEL_H

#include "navaidspoint.h"

#include <QAbstractListModel>
#include <QFile>
#include <QTextStream>

#include <QDebug>

class NavaidsModel : public QAbstractListModel
{
    Q_OBJECT
public:
    NavaidsModel(QObject *parent = Q_NULLPTR):QAbstractListModel(parent){
    }
    enum NavaidsRoles {
        PositionRole = Qt::UserRole + 1,
        OACICodeRole,
        CountryCodeRole
    };

    void readFromCSV(const QString &filename){
        QFile file(filename);
        if(!file.open(QFile::ReadOnly | QFile::Text))
            return;
        QTextStream in(&file);
        while (!in.atEnd()) {
            QString line = in.readLine();
            QStringList elements = line.split(",");
            if(elements.count()==4){
                QString code = elements[0];
                double latitude = elements[1].toDouble();
                double longitude = elements[2].toDouble();
                QString country = elements[3];
                NavaidsPoint p(code, latitude, longitude, country);
                addNavaidsPoint(p);
            }
        }
    }

    void addNavaidsPoint(const NavaidsPoint &point){
        beginInsertRows(QModelIndex(), rowCount(), rowCount());
        mPoints << point;
        endInsertRows();
    }

    int rowCount(const QModelIndex & parent = QModelIndex()) const{
        Q_UNUSED(parent)
        return mPoints.count();
    }

    QVariant data(const QModelIndex & index, int role=Qt::DisplayRole) const {
        if (index.row() < 0 || index.row() >= mPoints.count())
            return QVariant();

        const NavaidsPoint &point = mPoints[index.row()];
        if (role == PositionRole)
            return QVariant::fromValue(point.position());
        else if (role == OACICodeRole)
            return point.oaciCode();
        else if (role == CountryCodeRole)
            return point.countryCode();
        return QVariant();
    }

protected:
    QHash<int, QByteArray> roleNames() const {
        QHash<int, QByteArray> roles;
        roles[PositionRole] = "position";
        roles[OACICodeRole] = "oaci";
        roles[CountryCodeRole] = "country";
        return roles;
    }
private:
    QList<NavaidsPoint> mPoints;
};

#endif // NAVAIDSMODEL_H

创建模型后,会添加模型并将其公开给QML:

#include "navaidsmodel.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    NavaidsModel model;
    model.readFromCSV("/home/eyllanesc/data.csv"); //from file

    model.addNavaidsPoint(NavaidsPoint("Oslo", 59.9154, 10.7425, "NG")); // add new point

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("navaidsModel", &model);
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

最后,MapItemView与相应的模型和委托一起使用:

import QtQuick 2.6
import QtQuick.Window 2.2
import QtPositioning 5.5
import QtLocation 5.6

Window {
    width: 700
    height: 500
    visible: true
    title: qsTr("Test implantation coordonnées")

    property variant topLeftEurope: QtPositioning.coordinate(60.5, 0.0)
    property variant bottomRightEurope: QtPositioning.coordinate(51.0, 14.0)
    property variant viewOfEurope:
        QtPositioning.rectangle(topLeftEurope, bottomRightEurope)

    Map {
        id: mapOfEurope
        anchors.centerIn: parent;
        anchors.fill: parent
        plugin: Plugin {
            name: "osm"
        }
        MapItemView {
            model: navaidsModel
            delegate: MapCircle{
                center: position
                radius: 10000
                color: 'green'
                border.width: 3
                MouseArea {
                    anchors.fill: parent
                    onDoubleClicked: {
                        console.log("Doubleclick on " + oaci)
                    }
                    onClicked: {
                        console.log("Point : " + oaci + " " + position + " " + country)
                    }
                }
            }
        }
        visibleRegion: viewOfEurope
    }
}

以下link是完整的示例。