I am currently creating a program that can mark places on the map.
map.qml:
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtLocation 5.6
import QtPositioning 5.6
Rectangle {
ListModel {
id: locationModel
}
Plugin {
id: mapPlugin
name: "esri"
}
Map {
id: place
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(51.5, 0.1)
zoomLevel: 7
MapItemView
{
model: locationModel
delegate: mapcomponent
}
}
Component {
id: mapcomponent
MapQuickItem {
id: marker
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
coordinate: QtPositioning.coordinate(lat, lon)
sourceItem: Image {
id: image
width: 100
height: 50
source: "qrc:/rec/marker.png"
}
}
}
function addPlace(lat: double, lon: double){
locationModel.append({"lat": lat, "lon": lon})
console.log("Done")
}
}
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->quickWidget->setSource(QUrl("qrc:/rec/map.qml"));
QQmlComponent component(ui->quickWidget->engine(), ui->quickWidget->source());
object = component.create();
}
/*Some not interesting code.*/
void MainWindow::on_pushButton_4_clicked()
{
double lat = 50.00;
double lon = 20.00;
QMetaObject::invokeMethod(object, "addDevice",
Q_ARG(double, lat),
Q_ARG(double, lon));
}
object
is defined in mainwindow.h like this: QObject *object;
.
The add place
function is called from a c ++ file when a certain button is clicked. Unfortunately, for some reason, this function does not work properly. After invoking it, the message "Done" appears in the console and the location of the point to be marked on the map is added to the ListModel. Unfortunately, the marker does not appear on the map. What am I doing wrong? I will be grateful for any advice.
The problem is that you are creating a new component with a new map and you are adding the markers to that new invisible map.
Instead of exposing QML objects to C++ it is better to do the opposite:
#ifndef PLACEHELPER_H
#define PLACEHELPER_H
#include <QObject>
class PlaceHelper : public QObject
{
Q_OBJECT
public:
explicit PlaceHelper(QObject *parent = nullptr);
void addPlace(double latitude, double longitude);
Q_SIGNALS:
void add(double latitude, double longitude);
};
#endif // PLACEHELPER_H
#include "placehelper.h"
PlaceHelper::PlaceHelper(QObject *parent) : QObject(parent)
{
}
void PlaceHelper::addPlace(double latitude, double longitude)
{
Q_EMIT add(latitude, longitude);
}
*.h
// ..
private:
Ui::MainWindow *ui;
PlaceHelper placeHelper;
};
*.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQmlContext>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->quickWidget->rootContext()->setContextProperty("placeHelper", &placeHelper);
ui->quickWidget->setSource(QUrl("qrc:/rec/map.qml"));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_4_clicked()
{
double lat = 50.00;
double lon = 0.10;
placeHelper.addPlace(lat, lon);
}
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtLocation 5.6
import QtPositioning 5.6
Rectangle {
ListModel {
id: locationModel
}
Plugin {
id: mapPlugin
name: "esri"
}
Map {
id: place
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(51.5, 0.1)
zoomLevel: 7
MapItemView
{
model: locationModel
delegate: mapcomponent
}
}
Component {
id: mapcomponent
MapQuickItem {
id: marker
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
coordinate: QtPositioning.coordinate(lat, lon)
sourceItem: Image {
id: image
width: 100
height: 50
source: "qrc:/rec/marker.png"
}
}
}
Connections{
target: placeHelper
function onAdd(latitude, longitude){
locationModel.append({"lat": latitude, "lon": longitude})
}
}
}
Another solution is for the model to be implemented in C ++ and exported to QML:
#ifndef PLACEMODEL_H
#define PLACEMODEL_H
#include <QStandardItemModel>
class PlaceModel: public QStandardItemModel
{
Q_OBJECT
public:
enum PlaceRoles {
LatitudeRole = Qt::UserRole + 1,
LongitudeRole
};
PlaceModel(QObject *parent=nullptr);
Q_INVOKABLE void addPlace(double longitude, double latitude);
};
#endif // PLACEMODEL_H
#include "placemodel.h"
PlaceModel::PlaceModel(QObject *parent):
QStandardItemModel(parent)
{
setItemRoleNames({{LatitudeRole, "lat"},
{LongitudeRole, "lon"}});
}
void PlaceModel::addPlace(double latitude, double longitude)
{
QStandardItem *item = new QStandardItem;
item->setData(latitude, LatitudeRole);
item->setData(longitude, LongitudeRole);
appendRow(item);
}
*.h
private:
Ui::MainWindow *ui;
PlaceModel placeModel;
*.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQmlContext>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->quickWidget->rootContext()->setContextProperty("placeModel", &placeModel);
ui->quickWidget->setSource(QUrl("qrc:/rec/map.qml"));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_4_clicked()
{
double lat = 50.00;
double lon = 0.10;
placeModel.addPlace(lat, lon);
}
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtLocation 5.6
import QtPositioning 5.6
Rectangle {
Plugin {
id: mapPlugin
name: "esri"
}
Map {
id: place
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(51.5, 0.1)
zoomLevel: 7
MapItemView
{
id: mapView
model: placeModel
delegate: mapcomponent
}
}
Component {
id: mapcomponent
MapQuickItem {
id: marker
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
coordinate: QtPositioning.coordinate(lat, lon)
sourceItem: Image {
id: image
width: 100
height: 50
source: "qrc:/rec/marker.png"
}
}
}
}