在 QML 中,(如何)我可以将 MapItemGroup 作为 MapItemView 的委托组件?
In QML, (how) can I make MapItemGroup as a MapItemView's delegate component?
情况: 我可以将 QML 地图项与 Model/View/delegate 一起使用。我可以处理单个项目。
问题: 作为下一步,我希望能够绘制多个项目。我需要在单个委托组件中放置多个 QML MapItems(如 MapCircle、MapRectangle 等)。通常,QML 支持一个委托中的多个项目。问题在于 MapItemView 的委托:它不支持多个子项。
我的方法:
我认为使用 MapItemGroup 会奏效。但似乎我错过了什么。关于如何使它作为委托组件工作的文档也不是很详尽。附加的片段显示了这个实现。
在下面的代码中:
- delegateCircle、delegateRect 工作正常
- delegateGroup 未显示
一个简单的实现:
import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3 as QQc2
QQc2.ApplicationWindow {
visible: true
width: 640
height: 480
// Some list model
ListModel {
id: someModel
ListElement {lat: 0; lon: 0}
ListElement {lat: 5; lon: 0}
ListElement {lat: 5; lon: 5}
ListElement {lat: 0; lon: 5}
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: QtPositioning.coordinate(2.5, 2.5)
zoomLevel: 6
// Some views to test the model
// delegateCircle, delegateRect work fine
// delegateGroup is not displayed
MapItemView {
model: someModel
delegate: MapCircle {
id: delegateCircle
border.color: "red"
border.width: 1
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 50*1000
}
}
MapItemView {
model: someModel
delegate: MapRectangle {
id: delegateRect
border.color: "green"
border.width: 3
topLeft : QtPositioning.coordinate(model.lat+1, model.lon-1)
bottomRight : QtPositioning.coordinate(model.lat-1, model.lon+1)
}
}
MapItemView {
model: someModel
delegate: MapItemGroup {
id: delegateGroup
MapCircle {
id: innerCircle
border.color: "green"
border.width: 3
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 75*1000
}
MapRectangle {
id: innerRect
border.color: "red"
border.width: 6
topLeft : QtPositioning.coordinate(model.lat+2, model.lon-2)
bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
}
}
}
}
}
以上代码的输出为:
- 我还尝试使用 MapItemGroup 作为 MapQuickItem 类型的 sourceItem。这也没有用。
我想达到的目标:
嗯。我需要使用 MapItemView 绘制多个地图项。欢迎任何其他 solution/method(包括 c++ 后端程序)。
编辑
谢谢@GrecKo 和@Yoann。您的两种解决方案都有效。但是,我选择继续使用 Instantiator,因为它更适合我的应用程序。
在看到您的解决方案后,我也发现这个很有趣:a developer's discussion on populating a model using Repeater and Instantiator。
您可以使用简单的 Repeater
而不是 MapItemView
import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3
ApplicationWindow {
visible: true
width: 640
height: 480
// Some list model
ListModel {
id: someModel
ListElement {lat: 0; lon: 0}
ListElement {lat: 5; lon: 0}
ListElement {lat: 5; lon: 5}
ListElement {lat: 0; lon: 5}
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: QtPositioning.coordinate(2.5, 2.5)
zoomLevel: 6
Repeater
{
model: someModel
MapItemGroup {
id: delegateGroup
MapCircle {
id: innerCircle
border.color: "green"
border.width: 3
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 75*1000
}
MapRectangle {
id: innerRect
border.color: "red"
border.width: 6
topLeft : QtPositioning.coordinate(model.lat+2, model.lon-2)
bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
}
Component.onCompleted: map.addMapItemGroup(this)
}
}
}
}
正如 GrecKo 指出的那样,为了使其与动态模型一起使用,必须将 itemGroup "manually" 添加到地图中,因此 Component.onCompleted: map.addMapItemGroup(this)
行
不幸的是,MapItemView
仅适用于 MapItem
衍生项目,MapItemGroup
不是其中之一。
您可以使用 Repeater
,它适用于从一开始就创建的委托,但如果您稍后在模型中添加行,它将不起作用。
我在 中解释了为什么 Repeater
不太适合 Map
。
在我的回答中,我建议使用 MapItemView
但它在这里不适用。
希望还有最后一个可用的解决方案:
Instantiator
with Map.addMapItemGroup() and Map.removeMapItemGroup().
import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3 as QQc2
import QtQml 2.2
QQc2.ApplicationWindow {
visible: true
width: 640
height: 480
ListModel {
id: someModel
ListElement {lat: 0; lon: 0}
ListElement {lat: 5; lon: 0}
ListElement {lat: 5; lon: 5}
ListElement {lat: 0; lon: 5}
}
Timer {
interval: 1000
running: true
repeat: true
property bool toggle: true
onTriggered: {
if (toggle)
someModel.append({lat: 2.5, lon: 2.5});
else
someModel.remove(4);
toggle = !toggle;
}
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: QtPositioning.coordinate(2.5, 2.5)
zoomLevel: 6
Instantiator {
model: someModel
delegate: MapItemGroup {
id: delegateGroup
MapCircle {
id: innerCircle
border.color: "green"
border.width: 3
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 75*1000
}
MapRectangle {
id: innerRect
border.color: "red"
border.width: 6
topLeft : QtPositioning.coordinate(model.lat+2, model.lon-2)
bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
}
}
onObjectAdded: map.addMapItemGroup(object)
onObjectRemoved: map.removeMapItemGroup(object)
}
}
}
那是 fixed in Qt 5.12,所以您可以像现在一样使用您的代码
import QtLocation 5.12
import QtPositioning 5.12
情况: 我可以将 QML 地图项与 Model/View/delegate 一起使用。我可以处理单个项目。
问题: 作为下一步,我希望能够绘制多个项目。我需要在单个委托组件中放置多个 QML MapItems(如 MapCircle、MapRectangle 等)。通常,QML 支持一个委托中的多个项目。问题在于 MapItemView 的委托:它不支持多个子项。
我的方法:
我认为使用 MapItemGroup 会奏效。但似乎我错过了什么。关于如何使它作为委托组件工作的文档也不是很详尽。附加的片段显示了这个实现。
在下面的代码中:
- delegateCircle、delegateRect 工作正常
- delegateGroup 未显示
一个简单的实现:
import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3 as QQc2
QQc2.ApplicationWindow {
visible: true
width: 640
height: 480
// Some list model
ListModel {
id: someModel
ListElement {lat: 0; lon: 0}
ListElement {lat: 5; lon: 0}
ListElement {lat: 5; lon: 5}
ListElement {lat: 0; lon: 5}
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: QtPositioning.coordinate(2.5, 2.5)
zoomLevel: 6
// Some views to test the model
// delegateCircle, delegateRect work fine
// delegateGroup is not displayed
MapItemView {
model: someModel
delegate: MapCircle {
id: delegateCircle
border.color: "red"
border.width: 1
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 50*1000
}
}
MapItemView {
model: someModel
delegate: MapRectangle {
id: delegateRect
border.color: "green"
border.width: 3
topLeft : QtPositioning.coordinate(model.lat+1, model.lon-1)
bottomRight : QtPositioning.coordinate(model.lat-1, model.lon+1)
}
}
MapItemView {
model: someModel
delegate: MapItemGroup {
id: delegateGroup
MapCircle {
id: innerCircle
border.color: "green"
border.width: 3
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 75*1000
}
MapRectangle {
id: innerRect
border.color: "red"
border.width: 6
topLeft : QtPositioning.coordinate(model.lat+2, model.lon-2)
bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
}
}
}
}
}
以上代码的输出为:
- 我还尝试使用 MapItemGroup 作为 MapQuickItem 类型的 sourceItem。这也没有用。
我想达到的目标:
嗯。我需要使用 MapItemView 绘制多个地图项。欢迎任何其他 solution/method(包括 c++ 后端程序)。
编辑
谢谢@GrecKo 和@Yoann。您的两种解决方案都有效。但是,我选择继续使用 Instantiator,因为它更适合我的应用程序。
在看到您的解决方案后,我也发现这个很有趣:a developer's discussion on populating a model using Repeater and Instantiator。
您可以使用简单的 Repeater
而不是 MapItemView
import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3
ApplicationWindow {
visible: true
width: 640
height: 480
// Some list model
ListModel {
id: someModel
ListElement {lat: 0; lon: 0}
ListElement {lat: 5; lon: 0}
ListElement {lat: 5; lon: 5}
ListElement {lat: 0; lon: 5}
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: QtPositioning.coordinate(2.5, 2.5)
zoomLevel: 6
Repeater
{
model: someModel
MapItemGroup {
id: delegateGroup
MapCircle {
id: innerCircle
border.color: "green"
border.width: 3
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 75*1000
}
MapRectangle {
id: innerRect
border.color: "red"
border.width: 6
topLeft : QtPositioning.coordinate(model.lat+2, model.lon-2)
bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
}
Component.onCompleted: map.addMapItemGroup(this)
}
}
}
}
正如 GrecKo 指出的那样,为了使其与动态模型一起使用,必须将 itemGroup "manually" 添加到地图中,因此 Component.onCompleted: map.addMapItemGroup(this)
不幸的是,MapItemView
仅适用于 MapItem
衍生项目,MapItemGroup
不是其中之一。
您可以使用 Repeater
,它适用于从一开始就创建的委托,但如果您稍后在模型中添加行,它将不起作用。
我在 Repeater
不太适合 Map
。
在我的回答中,我建议使用 MapItemView
但它在这里不适用。
希望还有最后一个可用的解决方案:
Instantiator
with Map.addMapItemGroup() and Map.removeMapItemGroup().
import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3 as QQc2
import QtQml 2.2
QQc2.ApplicationWindow {
visible: true
width: 640
height: 480
ListModel {
id: someModel
ListElement {lat: 0; lon: 0}
ListElement {lat: 5; lon: 0}
ListElement {lat: 5; lon: 5}
ListElement {lat: 0; lon: 5}
}
Timer {
interval: 1000
running: true
repeat: true
property bool toggle: true
onTriggered: {
if (toggle)
someModel.append({lat: 2.5, lon: 2.5});
else
someModel.remove(4);
toggle = !toggle;
}
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: QtPositioning.coordinate(2.5, 2.5)
zoomLevel: 6
Instantiator {
model: someModel
delegate: MapItemGroup {
id: delegateGroup
MapCircle {
id: innerCircle
border.color: "green"
border.width: 3
center: QtPositioning.coordinate(model.lat, model.lon)
radius: 75*1000
}
MapRectangle {
id: innerRect
border.color: "red"
border.width: 6
topLeft : QtPositioning.coordinate(model.lat+2, model.lon-2)
bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
}
}
onObjectAdded: map.addMapItemGroup(object)
onObjectRemoved: map.removeMapItemGroup(object)
}
}
}
那是 fixed in Qt 5.12,所以您可以像现在一样使用您的代码
import QtLocation 5.12
import QtPositioning 5.12