QT通过C++添加Map QML Items
QT add Map QML Items via C++
我尝试将 C++ 中的 MapQuickItem 或 MapCircle 等 QML 地图项添加到我的地图中。
不幸的是,它们没有显示在地图上。只需一个 QML 矩形的相同代码就可以工作。
rect v1 是用于测试的矩形。 rect v2 是不起作用的 mapCircle。
当我将我的圈子 QML 代码 1:1 添加到我的地图 QML 代码中时,它工作正常。
main.cpp:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView *view = new QQuickView;
view->setSource(QUrl("qrc:/map.qml"));
QQmlComponent compRect (view->engine(), QUrl("qrc:/rect.qml"));
view->setWidth(1000);
view->setHeight(650);
view->setTitle("GUI");
QQuickItem *map = view->findChild<QQuickItem*>("map1");
QQuickItem *rect = qobject_cast<QQuickItem*>(compRect.create(view->rootContext()));
rect->setParentItem(map);
rect->setParent(map); //know this is not for visual objects, just for test
view->show();
return app.exec();
}
rect.qml v1
import QtQuick 2.14
import QtLocation 5.14
import QtPositioning 5.14
Rectangle
{
color: "grey"
opacity: .8
width: 100
height: 100
radius: 4
Text
{
id: text
anchors.centerIn: parent
text: "hi"
color: "orangered"
font.weight: Font.Bold
}
}
rect.qml v2
import QtQuick 2.14
import QtLocation 5.14
import QtPositioning 5.14
MapCircle
{
center
{
latitude: 47.5
longitude: 8.9
}
radius: 5000.0
color: 'green'
border.width: 3
}
map.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtPositioning 5.14
import QtLocation 5.14
Map
{
objectName: "map1"
id: map_map
anchors.centerIn: parent;
anchors.fill: parent
plugin: Plugin
{
name: "mapboxgl" // "osm", "esri", ...
}
center: QtPositioning.coordinate(47.6,9.5)
zoomLevel: 8
// get position of device and set map center to it
PositionSource
{
active: true
onPositionChanged:
{
map.center(position.coordinate)
console.log(position.coordinate)
}
}
Timer
{
id: timerReload
interval: 1000
repeat: true
running: true
onTriggered:
{
controller.triggerReload();
}
}
}
确定某个项目是地图的子项并不意味着它显示在地图上,如果您想添加一个项目,您必须使用 addMapItem()
method and in C++ you can use QMetaObject::invokeMethod()
来调用该方法但是您需要访问属于私有 Qt API 的类型 QDeclarativeGeoMapItemBase
,考虑到上述解决方案是:
*.pro
QT += quick location location-private
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp
RESOURCES += qml.qrc
main.cpp
#include <QGuiApplication>
#include <QQuickItem>
#include <QQuickView>
#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
int main(int argc, char *argv[]){
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl("qrc:/map.qml"));
view.resize(1000, 650);
view.setTitle("GUI");
view.show();
if(QQuickItem *map = view.findChild<QQuickItem*>("map1")){
QQmlComponent component(view.engine(), QUrl("qrc:/rect.qml"));
if(QDeclarativeGeoMapItemBase *rect = qobject_cast<QDeclarativeGeoMapItemBase*>(component.create(view.rootContext()))){
bool status = QMetaObject::invokeMethod(map,
"addMapItem",
Qt::DirectConnection,
Q_ARG(QDeclarativeGeoMapItemBase*, rect));
Q_ASSERT(status);
}
}
return app.exec();
}
前一种方法的问题是很危险,因为地图或任何QML元素随时都可能被移除,这样就可能产生问题,而且限制了QML的修改,最后是必须的访问私有 Qt API 可以更改,恕不另行通知。因此我会提供更好的选择:
使用 QObject 并将其导出到 QML,在 QML 中创建项目并将其添加到地图:
#include <QGuiApplication>
#include <QQuickView>
#include <QGeoCoordinate>
#include <QQmlContext>
class Helper: public QObject{
Q_OBJECT
public:
void addCircle(const QGeoCoordinate & coordinate){
Q_EMIT circleSignal(coordinate);
}
Q_SIGNALS:
void circleSignal(const QGeoCoordinate & coordinate);
};
int main(int argc, char *argv[]){
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQuickView view;
Helper helper;
view.rootContext()->setContextProperty("helper", &helper);
view.setSource(QUrl("qrc:/map.qml"));
view.resize(1000, 650);
view.setTitle("GUI");
view.show();
helper.addCircle(QGeoCoordinate(47.6, 9.5));
return app.exec();
}
#include "main.moc"
import QtQuick 2.14
import QtPositioning 5.14
import QtLocation 5.14
Map{
id: map_map
anchors.centerIn: parent;
anchors.fill: parent
plugin: Plugin {
name: "mapboxgl" // "osm", "esri", ...
}
center: QtPositioning.coordinate(47.6,9.5)
zoomLevel: 8
Connections{
target: helper
onCircleSignal: {
var component = Qt.createComponent("rect.qml");
if (component.status === Component.Ready){
var o = component.createObject(map_map);
o.center = coordinate
map_map.addMapItem(o)
}
}
}
}
或
import QtQuick 2.14
import QtPositioning 5.14
import QtLocation 5.14
Map{
id: map_map
anchors.centerIn: parent;
anchors.fill: parent
plugin: Plugin {
name: "mapboxgl" // "osm", "esri", ...
}
center: QtPositioning.coordinate(47.6,9.5)
zoomLevel: 8
Component{
id: provider
MapCircle{
center{
latitude: 47.6
longitude: 9.5
}
radius: 5000.0
color: 'green'
border.width: 3
}
}
function createCirle(map, position){
var o = provider.createObject(map)
o.center = position
map.addMapItem(o)
return o
}
Connections{
target: helper
onCircleSignal: {
var o = createCirle(map_map, coordinate)
}
}
}
将模型与 MapItemView 结合使用:
#include <QGuiApplication>
#include <QQuickView>
#include <QGeoCoordinate>
#include <QQmlContext>
#include <QStandardItemModel>
int CoordinateRole = Qt::UserRole + 1000;
int main(int argc, char *argv[]){
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQuickView view;
QStandardItemModel model;
QHash<int, QByteArray> roles;
roles[CoordinateRole] = QByteArray("coordinate");
model.setItemRoleNames(roles);
view.rootContext()->setContextProperty("circle_model", &model);
view.setSource(QUrl("qrc:/map.qml"));
view.resize(1000, 650);
view.setTitle("GUI");
view.show();
QStandardItem *item = new QStandardItem;
item->setData(QVariant::fromValue(QGeoCoordinate(47.6, 9.5)), CoordinateRole);
model.appendRow(item);
return app.exec();
}
import QtQuick 2.14
import QtPositioning 5.14
import QtLocation 5.14
Map{
id: map_map
anchors.centerIn: parent;
anchors.fill: parent
plugin: Plugin {
name: "mapboxgl" // "osm", "esri", ...
}
center: QtPositioning.coordinate(47.6,9.5)
zoomLevel: 8
MapItemView{
model: circle_model
delegate: MapCircle{
center: model.coordinate
radius: 5000.0
color: 'green'
border.width: 3
}
}
}
我尝试将 C++ 中的 MapQuickItem 或 MapCircle 等 QML 地图项添加到我的地图中。 不幸的是,它们没有显示在地图上。只需一个 QML 矩形的相同代码就可以工作。 rect v1 是用于测试的矩形。 rect v2 是不起作用的 mapCircle。 当我将我的圈子 QML 代码 1:1 添加到我的地图 QML 代码中时,它工作正常。
main.cpp:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView *view = new QQuickView;
view->setSource(QUrl("qrc:/map.qml"));
QQmlComponent compRect (view->engine(), QUrl("qrc:/rect.qml"));
view->setWidth(1000);
view->setHeight(650);
view->setTitle("GUI");
QQuickItem *map = view->findChild<QQuickItem*>("map1");
QQuickItem *rect = qobject_cast<QQuickItem*>(compRect.create(view->rootContext()));
rect->setParentItem(map);
rect->setParent(map); //know this is not for visual objects, just for test
view->show();
return app.exec();
}
rect.qml v1
import QtQuick 2.14
import QtLocation 5.14
import QtPositioning 5.14
Rectangle
{
color: "grey"
opacity: .8
width: 100
height: 100
radius: 4
Text
{
id: text
anchors.centerIn: parent
text: "hi"
color: "orangered"
font.weight: Font.Bold
}
}
rect.qml v2
import QtQuick 2.14
import QtLocation 5.14
import QtPositioning 5.14
MapCircle
{
center
{
latitude: 47.5
longitude: 8.9
}
radius: 5000.0
color: 'green'
border.width: 3
}
map.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtPositioning 5.14
import QtLocation 5.14
Map
{
objectName: "map1"
id: map_map
anchors.centerIn: parent;
anchors.fill: parent
plugin: Plugin
{
name: "mapboxgl" // "osm", "esri", ...
}
center: QtPositioning.coordinate(47.6,9.5)
zoomLevel: 8
// get position of device and set map center to it
PositionSource
{
active: true
onPositionChanged:
{
map.center(position.coordinate)
console.log(position.coordinate)
}
}
Timer
{
id: timerReload
interval: 1000
repeat: true
running: true
onTriggered:
{
controller.triggerReload();
}
}
}
确定某个项目是地图的子项并不意味着它显示在地图上,如果您想添加一个项目,您必须使用 addMapItem()
method and in C++ you can use QMetaObject::invokeMethod()
来调用该方法但是您需要访问属于私有 Qt API 的类型 QDeclarativeGeoMapItemBase
,考虑到上述解决方案是:
*.pro
QT += quick location location-private
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp
RESOURCES += qml.qrc
main.cpp
#include <QGuiApplication>
#include <QQuickItem>
#include <QQuickView>
#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
int main(int argc, char *argv[]){
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl("qrc:/map.qml"));
view.resize(1000, 650);
view.setTitle("GUI");
view.show();
if(QQuickItem *map = view.findChild<QQuickItem*>("map1")){
QQmlComponent component(view.engine(), QUrl("qrc:/rect.qml"));
if(QDeclarativeGeoMapItemBase *rect = qobject_cast<QDeclarativeGeoMapItemBase*>(component.create(view.rootContext()))){
bool status = QMetaObject::invokeMethod(map,
"addMapItem",
Qt::DirectConnection,
Q_ARG(QDeclarativeGeoMapItemBase*, rect));
Q_ASSERT(status);
}
}
return app.exec();
}
前一种方法的问题是很危险,因为地图或任何QML元素随时都可能被移除,这样就可能产生问题,而且限制了QML的修改,最后是必须的访问私有 Qt API 可以更改,恕不另行通知。因此我会提供更好的选择:
使用 QObject 并将其导出到 QML,在 QML 中创建项目并将其添加到地图:
#include <QGuiApplication> #include <QQuickView> #include <QGeoCoordinate> #include <QQmlContext> class Helper: public QObject{ Q_OBJECT public: void addCircle(const QGeoCoordinate & coordinate){ Q_EMIT circleSignal(coordinate); } Q_SIGNALS: void circleSignal(const QGeoCoordinate & coordinate); }; int main(int argc, char *argv[]){ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQuickView view; Helper helper; view.rootContext()->setContextProperty("helper", &helper); view.setSource(QUrl("qrc:/map.qml")); view.resize(1000, 650); view.setTitle("GUI"); view.show(); helper.addCircle(QGeoCoordinate(47.6, 9.5)); return app.exec(); } #include "main.moc"
import QtQuick 2.14 import QtPositioning 5.14 import QtLocation 5.14 Map{ id: map_map anchors.centerIn: parent; anchors.fill: parent plugin: Plugin { name: "mapboxgl" // "osm", "esri", ... } center: QtPositioning.coordinate(47.6,9.5) zoomLevel: 8 Connections{ target: helper onCircleSignal: { var component = Qt.createComponent("rect.qml"); if (component.status === Component.Ready){ var o = component.createObject(map_map); o.center = coordinate map_map.addMapItem(o) } } } }
或
import QtQuick 2.14 import QtPositioning 5.14 import QtLocation 5.14 Map{ id: map_map anchors.centerIn: parent; anchors.fill: parent plugin: Plugin { name: "mapboxgl" // "osm", "esri", ... } center: QtPositioning.coordinate(47.6,9.5) zoomLevel: 8 Component{ id: provider MapCircle{ center{ latitude: 47.6 longitude: 9.5 } radius: 5000.0 color: 'green' border.width: 3 } } function createCirle(map, position){ var o = provider.createObject(map) o.center = position map.addMapItem(o) return o } Connections{ target: helper onCircleSignal: { var o = createCirle(map_map, coordinate) } } }
将模型与 MapItemView 结合使用:
#include <QGuiApplication> #include <QQuickView> #include <QGeoCoordinate> #include <QQmlContext> #include <QStandardItemModel> int CoordinateRole = Qt::UserRole + 1000; int main(int argc, char *argv[]){ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQuickView view; QStandardItemModel model; QHash<int, QByteArray> roles; roles[CoordinateRole] = QByteArray("coordinate"); model.setItemRoleNames(roles); view.rootContext()->setContextProperty("circle_model", &model); view.setSource(QUrl("qrc:/map.qml")); view.resize(1000, 650); view.setTitle("GUI"); view.show(); QStandardItem *item = new QStandardItem; item->setData(QVariant::fromValue(QGeoCoordinate(47.6, 9.5)), CoordinateRole); model.appendRow(item); return app.exec(); }
import QtQuick 2.14 import QtPositioning 5.14 import QtLocation 5.14 Map{ id: map_map anchors.centerIn: parent; anchors.fill: parent plugin: Plugin { name: "mapboxgl" // "osm", "esri", ... } center: QtPositioning.coordinate(47.6,9.5) zoomLevel: 8 MapItemView{ model: circle_model delegate: MapCircle{ center: model.coordinate radius: 5000.0 color: 'green' border.width: 3 } } }