Dynamically change custom host URL of osm Plugin in a QML Map - qt

I have a custom chart host with several tiled maps in a directory structure:
http://host/New_York/
http://host/Washington/
http://host/Montreal/
The QML application has a ComboBox component that allows the user to select which chart he wants to display.
The Map component uses the osm Plugin with a PluginParameter pointing to the URL to use for the chart. I thought I could simply dynamically assign a value to this PluginParameter, but it does not work, the value remains unchanged even after assigning it. I also tried destroying the Plugin object, recreating it and assigning it to the Map object, but I get an error saying that the plugin property is ReadOnly.
What is the proper way to dynamically change the custom host URL of a Plugin object used by a Map component?
Plugin {
id: mapPlugin
name: "osm"
PluginParameter { id: charturl; name: "osm.mapping.custom.host"; }
}
Map {
id: mapview
plugin: mapPlugin
activeMapType: supportedMapTypes[supportedMapTypes.length - 1]
...
ComboBox {
...
onCurrentIndexChanged: {
charturl.value = cbItems.get(currentIndex).url
...

The Plugin can only be written once, so you cannot change it later, so in this you will have to create a new map using Loader:
main.qml
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.14
import QtLocation 5.14
import QtPositioning 5.14
Window {
visible: true
width: 640
height: 480
ColumnLayout {
anchors.fill: parent
ComboBox {
id: combobox
model: [
"http://host/New_York/",
"http://host/Washington/",
"http://host/Montreal/"
]
Layout.fillWidth: true
onActivated: changeHost()
}
Loader{
id: loader
Layout.fillWidth: true
Layout.fillHeight: true
onStatusChanged: if (loader.status === Loader.Ready) console.log('Loaded')
}
Component.onCompleted: changeHost()
}
function changeHost(){
var item = loader.item
var zoomLevel = item ? item.zoomLevel: 14
var center = item ? item.center: QtPositioning.coordinate(59.91, 10.75)
loader.setSource("MapComponent.qml", {
"host": combobox.currentValue,
"center": center,
"zoomLevel": zoomLevel}
)
}
}
MapComponent.qml
import QtLocation 5.14
Map {
id: map
property string host: ""
plugin: Plugin {
name: "osm"
PluginParameter {
name: "osm.mapping.custom.host"
value: map.host
}
}
activeMapType: supportedMapTypes[supportedMapTypes.length - 1]
}

Related

QML Custom Tile server

I'm trying to plot an offline map using a custom server that my machine is hosting. I've followed the steps of this project for docker. It works when I use my browser (http://localhost:8080/). But when I try to access QML using the code below I just get a Static image GPS output
.
What am I doing wrong? I should see Zambia with a good resolution as I see in the Browser.
QML CODE
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.VirtualKeyboard 2.4
import QtLocation 5.11
ApplicationWindow {
id: window
width: 640
height: 480
visible: true
title: qsTr("GPS")
Plugin{
id: plugin_osm
name: "osm"
PluginParameter {
name: "osm.mapping.custom.host"
value: "http://localhost:8080"
}
/*disable retrieval of the providers information from the remote repository.
If this parameter is not set to true (as shown here), then while offline,
network errors will be generated at run time*/
PluginParameter {
name: "osm.mapping.providersrepository.disabled"
value: true
}
}
Map {
id: map
anchors.fill: parent
plugin: plugin_osm
zoomLevel: 12
minimumZoomLevel: 5
maximumZoomLevel: 17
center: QtPositioning.coordinate(54.2,16.2)
activeMapType: supportedMapTypes[supportedMapTypes.length - 1]
}
}
You have 2 errors:
The host is wrong.
The coordinate is not to Zambia but to Poland
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
ApplicationWindow {
id: window
width: 640
height: 480
visible: true
title: qsTr("GPS")
Plugin {
id: plugin_osm
name: "osm"
PluginParameter {
name: "osm.mapping.custom.host"
value: "http://localhost/tile/"
}
/*disable retrieval of the providers information from the remote repository.
If this parameter is not set to true (as shown here), then while offline,
network errors will be generated at run time*/
PluginParameter {
name: "osm.mapping.providersrepository.disabled"
value: true
}
}
Map {
id: map
anchors.fill: parent
plugin: plugin_osm
zoomLevel: 12
minimumZoomLevel: 5
maximumZoomLevel: 17
center: QtPositioning.coordinate(-15.4067, 28.2871)
activeMapType: supportedMapTypes[supportedMapTypes.length - 1]
}
}
Output:

Zoomlevel in qml map using osm plugin

I have a qml map that uses osm plugin and it is in offline mode. I noticed that the maximum zoomlevel is 19 and I want to increase it. How can I change the maximum zoomlevel using this plugin?
Is there a solution?
import QtQuick.Window 2.12
import QtQuick 2.0
import QtLocation 5.11
import QtPositioning 5.11
import QtQuick.Controls 2.5
import QtQuick.Controls.Styles 1.4
Window {
visible: true
width: 640
height: 480
Plugin {
id: mapPlugin
name: "osm"
PluginParameter {
name: "osm.mapping.custom.host"
value: "file:///home/mahmud/Maps/humanitarian/" // this is the directory of map tiles
}
PluginParameter {
name: "osm.mapping.providersrepository.disabled"
value: true
}
}
Map {
id: map
anchors.fill: parent
width: parent.width
height:parent.height
plugin: mapPlugin
center: QtPositioning.coordinate(32.4279, 53.6880) // Oslo
zoomLevel: 6
maximumZoomLevel: 30
onZoomLevelChanged: {
console.log(map.zoomLevel)
}
Component.onCompleted: {
for( var i_type in supportedMapTypes ) {
if( supportedMapTypes[i_type].name.localeCompare( "Custom URL Map" ) === 0 ) {
activeMapType = supportedMapTypes[i_type]
}
}
}
}
}

Displaying Marker in QT QML Map

I'm trying to add marker in QT QML Map. This is the code that I use to add a marker in Map, but the marker is not displaying. Please do help! I'm a beginner in QT Programming. Sorry for my grammar. Thank you!
Plugin {
id: mapPlugin
name: "osm"
}
function addMarker(latitude, longitude)
{
var Component = Qt.createComponent("qrc:///views/marker.qml")
var Item = Component.createObject(window, { coordinate:
QtPositioning.coordinate(latitude, longitude) })
Map.addMapItem(Item)
}
Map {
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(59.14, 14.15)
zoomLevel: 14
Component.onCompleted:
{
addMarker(59.14, 14.15)
}
}
Marker.qml
MapQuickItem
{
id: marker
anchorPoint.x: marker.width / 4
anchorPoint.y: marker.height
sourceItem: Image
{
Image
{
id: icon
source: "marker.png"
sourceSize.width: 40
sourceSize.height: 40
}
}
}
You have to use the ids to refer to the components, for example if you had Map and run Map.addMapItem(...) to what Map would the item be added ?. On the other hand you have a bad habit: you use names of existing elements such as Item that is already a type, in this case change it to item to avoid confusion, considering the above the solution is:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtLocation 5.12
import QtPositioning 5.12
Window {
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Plugin {
id: mapPlugin
name: "osm"
}
function addMarker(latitude, longitude)
{
var Component = Qt.createComponent("qrc:///views/marker.qml")
var item = Component.createObject(window, {
coordinate: QtPositioning.coordinate(latitude, longitude)
})
map.addMapItem(item)
}
Map {
id: map
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(59.14, 14.15)
zoomLevel: 14
Component.onCompleted:addMarker(59.14, 14.15)
}
}
On the other hand in marker you point out that an Image has as a child another Image, do you think it is correct?, it is not necessary so the corrected Marker code is:
import QtQuick 2.0
import QtLocation 5.12
MapQuickItem{
id: marker
anchorPoint.x: marker.width / 4
anchorPoint.y: marker.height
sourceItem: Image{
id: icon
source: "marker.png"
sourceSize.width: 40
sourceSize.height: 40
}
}
The complete example is in the following link

How to set an item property of one qml from main.qml

I waste my time to find how set the visible property to false, the delegate being in an another qml file.
For instance here is a simple example based on Places Map.
Marker.qml
import QtQuick 2.0
import QtLocation 5.6
MapQuickItem {
id: idPointsMarker
sourceItem: Loader{sourceComponent: idRect}
visible: true //if set manually to false, everything works correctly
Component{
id: idRect
Rectangle{
width: 20
height: 20
color: "blue"
}
}
}
and the main.qml
import QtQuick 2.0
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6
Window {
width: 512
height: 512
visible: true
PositionSource {
...
}
property variant locationOslo: QtPositioning.coordinate( 59.93, 10.76)
PlaceSearchModel {
...
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: locationOslo
zoomLevel: 13
MouseArea {
id : mouseMap
anchors.fill: parent
onDoubleClicked: {
console.log("DoubleClicked")
Marker.idPointsMarker.visible = false // pb is here
}
}
MapItemView {
model: searchModel
delegate: Marker{
coordinate: place.location.coordinate
}
}
}
}
I wish to toggle the visibility to false on doubleclick. I am not able to access the property anyhow the way i write it. What is the correct syntax?
Sorry for a so simple question. Thanks for help.
You do not have to set the property in main.qml, you must do it in Marker.qml, since the elements of Marker.qml can access all the elements of main.qml. One solution is to establish a property of type bool that manages the visibility and that changes in the double click:
main.qml
Map {
[...]
property bool isVisibleItems: true
MouseArea {
id : mouseMap
anchors.fill: parent
onDoubleClicked: map.isVisibleItems = !map.isVisibleItems
}
[...]
Marker.qml
import QtQuick 2.0
import QtLocation 5.6
MapQuickItem {
id: idPointsMarker
sourceItem: Loader{sourceComponent: idRect}
visible: map.isVisibleItems
Component{
id: idRect
Rectangle{
width: 20
height: 20
color: "blue"
}
}
}
In the following link there is an example

How to setup my button component to open a window

Here is the code of the window I wanna be opened in file PopUpFreeCoins.qml:
import QtQuick 2.0
import QtQuick.Controls 2.1
Item {
property int t
property int c
ListModel{
id:ff
ListElement {
name: "ByFollow"
s: "Images/follow.png"
}
ListElement {
name: "ByLike"
s: "Images/care.png"
}
ListElement {
name: "ByComment"
s: "Images/chat.png"
}
}
ListView{
width:t-t/10
height: c/5
layoutDirection:Qt.LeftToRight
orientation: ListView.Horizontal
model: ff
spacing:50
delegate: Button{
contentItem: Image{
source: s
}}
}
}
property t is set equal to window width in main file and property c is set to window height. This is code of my Button.qml:
Button{//Below Right
width:profilePicture.width/2
height:profilePicture.width/2
x:profilePicture.x+profilePicture.width
y:profilePicture.y+profilePicture.height
contentItem: Image {
source: "Images/freecoins.png"
anchors.fill: parent
}
onClicked: PopUp{height:100;width:300;PopUpFreeCoins{t:a;c:b;}}
}
property a is window width and b is window height.
this line onClicked: PopUp{height:100;width:300;PopUpFreeCoins{t:a;c:b;}} has an error I don't know how to handle!
Here is the error:
Cannot assign object type PopUpFreeCoins_QMLTYPE_0 with no default
method
You need to create the Object somehow. You have multiple ways for dynamically create Objects. One way is to use Component.createObject(parent) which requires you to have a Component instantiated in your file.
Here you can also pass a Object ({property0 : value, property1:value ... }) as second argument, to set the properties of the Component to be instantiated. You should not set the parent to null as it might happen, that the JS-garbage collector is too aggressive once again.
Alternatively you can use the Loader to load it from either a source (QML-file) or sourceComponent. Here you won't have problems with the garbage collector.
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
width: 1024
height: 800
visible: true
Button {
text: 'create'
onClicked: test.createObject(this)
}
Button {
x: 200
text: 'load'
onClicked: loader.active = !loader.active
}
Loader {
id: loader
source: 'TestObj.qml'
active: false
}
Component {
id: test
TestObj {}
}
}
TestObj.qml includes the Window to be opened.
Alternatively you can have the Window created from the beginning, and just change the visible to true or false.

Resources