aszan
aszan

Reputation: 15

Adding new places to the QML map is not working

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.

Upvotes: -1

Views: 762

Answers (1)

eyllanesc
eyllanesc

Reputation: 243945

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"
            }
        }
    }
}

Upvotes: 0

Related Questions