I have a Qt application, I use Quick Widget, that displays a map using QtLocation and QtPositioning. I am trying to add circles to the map using coordinates from an array passed from C++. The circles should appear on the map when the component loads.
Here is my QML code:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
import QtQuick.Layouts 1.15
Rectangle {
id: rec
function addCircle(latitude, longitude, radius) {
map.addCircle(latitude, longitude, radius)
}
width: 800
height: 600
Plugin {
id: mapPlugin
name: "osm"
PluginParameter {
name: "osm.mapping.custom.host"
value: "https://tile.openstreetmap.org/"
}
}
Map {
id: map
property MapCircle circle
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(70, -175.5)
zoomLevel: 6
Component.onCompleted: {
for (var i = 0; i < myArray.length; i += 2) {
console.log(QtPositioning.coordinate(myArray[i], myArray[i + 1]));
var circle = Qt.createQmlObject('import QtPositioning 5.6; import QtLocation 5.6; MapCircle { }', map);
circle.center = QtPositioning.coordinate(myArray[i], myArray[i + 1]);
circle.radius = 5000;
circle.color = 'red';
circle.z = 1000;
console.log(circle.center, circle.radius);
map.addMapItem(circle);
console.log("Circle added:", circle);
}
}
}
}
And here is my main C++ file:
#include "mainwindow.h"
#include "GSN_model.h"
#include "for_SQLite_db.h"
#include "mapcontroller.h"
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QVariantList>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
// Creating the list
QVariantList myArray;
myArray << 70.3 << -175.4 << 69.3 << -175.4 << 71 << -175.4 ;
// Registering the list in the QML context
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("myArray", myArray);
const QUrl url(QStringLiteral("qrc:/map.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&a, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
w.show();
return a.exec();
}
The circles are supposed to be added to the map at startup, and the log shows that they are indeed being added:
qml: 70° 18' 0.0" N, 175° 24' 0.0" W
qml: 70° 18' 0.0" N, 175° 24' 0.0" W 5000
qml: Circle added: QDeclarativeCircleMapItem(0x243b9fe9c80)
qml: 69° 18' 0.0" N, 175° 24' 0.0" W
qml: 69° 18' 0.0" N, 175° 24' 0.0" W 5000
qml: Circle added: QDeclarativeCircleMapItem(0x243b9fea100)
qml: 71° 0' 0.0" N, 175° 24' 0.0" W
qml: 71° 0' 0.0" N, 175° 24' 0.0" W 5000
qml: Circle added: QDeclarativeCircleMapItem(0x243b9feb000)
However, the circles do not appear on the map. What am I doing wrong? How can I correctly add circles to the map in QtLocation?
I tried calling a function from QML
main.cpp
QQmlApplicationEngine engine;
MapController mapController;
engine.rootContext()->setContextProperty("mapController", &mapController);
const QUrl url(QStringLiteral("qrc:/map.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&a, [url, &mapController](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
mapController.setRootObject(obj);
mapController.drawCircle(70.6, -175.6, 10000.0);
mapController.drawCircle(70.3, -175.4, 5000000);
}, Qt::QueuedConnection);
engine.load(url);
mapcontoller.h
#ifndef MAPCONTROLLER_H
#define MAPCONTROLLER_H
#include <QObject>
#include <QGeoCoordinate>
class MapController : public QObject {
Q_OBJECT
public:
explicit MapController(QObject *parent = nullptr);
Q_INVOKABLE void drawCircle(double latitude, double longitude, double radius);
void setRootObject(QObject *rootObject);
private:
QObject *m_rootObject;
};
#endif // MAPCONTROLLER_H
mapcontoller.cpp
#include "mapcontroller.h"
#include <QQmlProperty>
#include <QDebug>
MapController::MapController(QObject *parent) : QObject(parent), m_rootObject(nullptr) {}
void MapController::setRootObject(QObject *rootObject) {
m_rootObject = rootObject;
}
void MapController::drawCircle(double latitude, double longitude, double radius) {
if (!m_rootObject) {
qWarning() << "Root object is not set!";
return;
}
QVariant returnedValue;
QVariant lat = latitude;
QVariant lon = longitude;
QVariant rad = radius;
QMetaObject::invokeMethod(m_rootObject, "addCircle",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, lat),
Q_ARG(QVariant, lon),
Q_ARG(QVariant, rad));
}
map.qml
...
Item {
id: circlesLayer
width: parent.width
height: parent.height
function addCircle(latitude, longitude, radius) {
console.log(QtPositioning.coordinate(latitude, longitude), radius);
var circle = Qt.createQmlObject('import QtPositioning 5.6; import QtLocation 5.6; MapCircle { }', map);
circle.center = QtPositioning.coordinate(latitude, longitude);
circle.radius = radius;
circle.color = 'red';
circle.z = 1000;
console.log(circle.center, circle.radius);
map.addMapItem(circle);
console.log("Circle added:", circle);
}
}
But I have encountered the same error
To make things simpler, I think you should return a 2D array as follows:
QVariantList myArray;
myArray << QVariant(QVariantList() << QVariant(70.3) << QVariant(-175.4));
myArray << QVariant(QVariantList() << QVariant(69.3) << QVariant(-175.4));
myArray << QVariant(QVariantList() << QVariant(71.3) << QVariant(-175.4));
// myArray = [[70.3,-175.4],[69.3,-175.4],[71.3,-175.4]]
Then, consume that array in a MapItemView
to create the MapCircle
, i.e.
Map {
anchors.fill: parent
plugin: Plugin { name: "osm" }
center: QtPositioning.coordinate(70, -175.5)
zoomLevel: 6
MapItemView {
model: myArray
delegate: MapCircle {
center: QtPositioning.coordinate(modelData[0], modelData[1])
radius: 10000.0
color: "red"
}
}
}