How to set Google Maps api in QML - qt

I'm having problem probably setting Google Maps Api in my code. My program needs to use google map satellite view and I have to add merkers, draw lines and other stuff like this. This is the code:
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6
Rectangle {
id: mainWindow
width: 512
height: 512
visible: true
ListModel{
id:dummyModel
ListElement {
Latitude: 47.212047
Longitude: -1.551647
Label: "something"
Orientation: 0
Color:"transparent"
}
}
Plugin {
id: googleMaps
name: "googlemaps" // "mapboxgl", "esri", ...
// specify plugin parameters if necessary
PluginParameter {
name:"googlemaps.maps.apikey"
value:"<*********************>" // here is the problem
}
}
Map {
id: myMap
anchors.fill: parent
plugin: googleMaps
activeMapType: supportedMapTypes[1]
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MapItemView{
id:dynamicMapObject
model: dummyModel
delegate: MapQuickItem {
coordinate: QtPositioning.coordinate(Latitude,Longitude)
sourceItem: Text{
width: 100
height: 50
text: model.Label
rotation: model.Orientation
opacity: 0.6
color: model.Color
}
}
}
MapPolyline {
line.width: 3
line.color: 'green'
path: [
{ latitude: 59.92, longitude: 10.77 },
{ latitude: 59.96, longitude: 10.78 },
{ latitude: 59.99, longitude: 10.76 },
{ latitude: 59.95, longitude: 10.74 }
]
}
MapCircle {
//a static item (fixed real dimension) always at 100m east of the map center
id:prova
center: myMap.center.atDistanceAndAzimuth(100,90)
opacity:0.8
color:"red"
radius:30
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton)
{
dummyModel.append({
"Latitude": myMap.toCoordinate(Qt.point(mouseX,mouseY)).latitude ,"Longitude": myMap.toCoordinate(Qt.point(mouseX,mouseY)).longitude ,
"Label": "abc" , "Color": "red",
"Orientation":Number(3), })
}
}
}
Button{
id:buttonMap
text:"Click to add name"
onClicked: {
if(buttonMap.text == "Click to add name")
{
buttonMap.text = "Click to cancel name"
myMap.activeMapType = myMap.supportedMapTypes[3]
}
else
{
buttonMap.text = "Click to add name"
myMap.activeMapType = myMap.supportedMapTypes[1]
}
}
}
GroupBox{
title:"map types"
ComboBox{
model:myMap.supportedMapTypes
textRole:"description"
onCurrentIndexChanged: myMap.activeMapType = myMap.supportedMapTypes[currentIndex]
}
}
}
When I compile the code in debug Mode everything works, but in release nothing is shown. Of course it's a problem of google api key. Does somebody know how to add them? I tried following this topic (https://forum.qt.io/topic/66725/open-source-map-plug-in-for-qml/24), but I can't get it works.
I also tried all the google maps api key available here (https://developers.google.com/maps/web/) but none of them works.
Does somebody know which api key is the correct one from the above for my purpose?
Am I missing something in the plugin parameters?
Thank you in advance!

Related

QML osm Plugin draw both path & items

How can I draw both item icons & path between points from model using QML and osm plugin?
XmlListModel {
...
}
Plugin {
id: mapPlugin
objectName: "mapPlugin"
name: "osm"
...
}
Map {
id: map
objectName: "map"
anchors.fill: parent
plugin: mapPlugin
MapItemView {
id: mapItemView
model: mapModel
// draw item icons
delegate: MapQuickItem {
coordinate: QtPositioning.coordinate( model.latitude, model.longitude )
...
}
// could draw lines between points, but unable to use two delegates
/* delegate: MapPolyline {
path: pathRole
line.color: "red"
line.width: 5
} */
}
One trick you could do is create two MapItemViews. One for drawing the icons and the other for drawing line segments connecting the two, i.e.
MapItemView { // for drawing icons
model: mapModel
}
MapItemView { // for drawing line segments
model: mapModel.count - 1
}
Here's a sample of how you may do this:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
Page {
Plugin {
id: mapPlugin
name: "osm"
}
Map {
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(43.0896, -79.0849)
zoomLevel: 12
MapItemView {
model: mapModel
delegate: MapQuickItem {
coordinate: QtPositioning.coordinate(lat, lon)
anchorPoint.x: 5
anchorPoint.y: 5
sourceItem: Rectangle {
width: 10
height: 10
color: "red"
border.color: "black"
}
}
}
MapItemView {
model: mapModel.count - 1
delegate: MapPolyline {
line.width: 3
line.color: "green"
path: [
{ latitude: mapModel.get(index).lat, longitude: mapModel.get(index).lon },
{ latitude: mapModel.get(index + 1).lat, longitude: mapModel.get(index + 1).lon }
]
}
}
}
ListModel {
id: mapModel
function appendCoordinate(lat, lon) {
append( {lat, lon} );
}
Component.onCompleted: {
appendCoordinate(43.0896, -79.0849);
appendCoordinate(43.0796, -79.0849);
appendCoordinate(43.0796, -79.0949);
}
}
}

Qt Select At Most 1 Marker on Map

In my code every marker that I clicked are selected(turn into green from red). I want just 1 can change. When I click another marker the marker I clicked before turns red again. Or When I click an empty area the marker I clicked before turns red again.
In qml my Item's code:
Component {
id: hazardous_img
MapQuickItem {
id: hazardousitem
anchorPoint.x: image.width/4
anchorPoint.y: image.height
coordinate: position
property bool isClicked: false
MouseArea {
anchors.fill: parent
onDoubleClicked: {
mainwindow.hazardousIconClicked(mapview.toCoordinate(Qt.point(mouse.x,mouse.y)))
}
onClicked: {
if (isClicked === false) {
image.source = "qrc:/grn-pushpin.png"
isClicked = true
} else {
image.source = "qrc:/red-pushpin.png"
isClicked = false
}
}
}
sourceItem: Image {
id: image
source: "qrc:/red-pushpin.png"
}
}
}
In QML this is usually done with using a ButtonGroup, but as you're not using AbstractButtons you need to write it yourself. Here is my solution for it.
I've used the ListModel to not only store the coordinates of each marker, but also a selected flag which is set to false by default. In the delegate I'm using the selected data role to show if a marker is selected or not.
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("Map")
ListModel { id: markerModel }
Plugin {
id: mapPlugin
name: "osm"
}
Map {
id: map
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MouseArea {
anchors.fill: parent
onDoubleClicked: {
var coordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y))
var jsonObject = JSON.parse(JSON.stringify(coordinate))
jsonObject["selected"] = false
markerModel.append(jsonObject)
}
onClicked: map.deselectAll()
}
MapItemView {
model: markerModel
delegate: markerDelegate
}
function deselectAll() {
for (var i = 0; i < markerModel.count; ++i)
markerModel.setProperty(i, "selected", false)
}
Component {
id: markerDelegate
MapQuickItem {
id: markerItem
required property int index
required property real latitude
required property real longitude
required property bool selected
anchorPoint.x: waypointMarker.width / 2
anchorPoint.y: waypointMarker.height / 2
coordinate: QtPositioning.coordinate(latitude, longitude)
sourceItem: Rectangle {
id: waypointMarker
width: 20
height: 20
radius: 20
border.width: 1
border.color: mouseArea.containsMouse ? "red" : "black"
color: markerItem.selected ? "red" : "gray"
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
map.deselectAll()
markerModel.setProperty(markerItem.index, "selected", true)
}
}
}
}
}
}
I came up with yet another solution without looping over all items in the model. It just stores the index of the selected marker in a dedicated property. This has the drawback that if the model order changes the index can become invalid, also potential multi selection is hard to handle, but on the other hand it is faster because it doesn't need to iterate over all items.
I experimented a lot with DelegateModel, it seems to be a perfect match if one could use it in combination with MapItemView, because of the groups and the attached properties like inGroupName.
After that I've tried ItemSelectionModel, but it seems it is only intended to be used in combination with a view, e.g. TreeView. I couldn't find out how to generate a QModelIndex in QML without a TreeView.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
ApplicationWindow {
id: root
width: 640
height: 480
visible: true
title: qsTr("Map")
property int selectedMarker: -1
Map {
id: map
anchors.fill: parent
plugin: Plugin {
id: mapPlugin
name: "osm"
}
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MouseArea {
anchors.fill: parent
onDoubleClicked: {
var coordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y))
markerModel.append(JSON.parse(JSON.stringify(coordinate)))
}
onClicked: root.selectedMarker = -1
}
MapItemView {
model: ListModel { id: markerModel }
delegate: markerDelegate
}
Component {
id: markerDelegate
MapQuickItem {
id: markerItem
required property int index
required property real latitude
required property real longitude
anchorPoint.x: waypointMarker.width / 2
anchorPoint.y: waypointMarker.height / 2
coordinate: QtPositioning.coordinate(latitude, longitude)
sourceItem: Rectangle {
id: waypointMarker
width: 20
height: 20
radius: 20
border.width: 1
border.color: mouseArea.containsMouse ? "red" : "black"
color: markerItem.index === root.selectedMarker ? "red" : "gray"
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: root.selectedMarker = markerItem.index
}
}
}
}
}
I promise this is the last answer on that question.
This one is using an ItemSelectionModel and a few undocumented functions, e.g. ListModel.index(row, col).
itemSelectionModel.hasSelection is used in the color binding to trigger a reevaluation in order to call isRowSelected and set the color accordingly whenever the selection has changed.
If the user clicks on the background the clear() is called to clear the selection.
I think out of the three this is the best solution. It can be easily upgraded to allow multi selection as shown below. Also the ItemSelectionModel can be used by other views to show the data and selection.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15
import QtQml.Models 2.15
ApplicationWindow {
id: root
width: 640
height: 480
visible: true
title: qsTr("Map")
Map {
id: map
anchors.fill: parent
plugin: Plugin {
id: mapPlugin
name: "osm"
}
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MouseArea {
anchors.fill: parent
onDoubleClicked: function(mouse) {
markerModel.append(map.toCoordinate(Qt.point(mouse.x, mouse.y)))
}
onClicked: itemSelectionModel.clear()
}
MapItemView {
model: ListModel { id: markerModel }
delegate: markerDelegate
}
ItemSelectionModel {
id: itemSelectionModel
model: markerModel
}
Component {
id: markerDelegate
MapQuickItem {
id: markerItem
required property int index
required property real latitude
required property real longitude
anchorPoint.x: waypointMarker.width / 2
anchorPoint.y: waypointMarker.height / 2
coordinate: QtPositioning.coordinate(latitude, longitude)
sourceItem: Rectangle {
id: waypointMarker
width: 20
height: 20
radius: 20
border.width: 1
border.color: mouseArea.containsMouse ? "red" : "black"
color: {
itemSelectionModel.hasSelection
return itemSelectionModel.isRowSelected(markerItem.index) ? "red" : "gray"
}
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: itemSelectionModel.select(markerModel.index(markerItem.index, 0),
ItemSelectionModel./*ClearAnd*/Select)
}
}
}
}
}

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

GeocodeModel in Qt

I'm writing a the little app with using the QT/QML, and i have problem with GeocodeModel in my app. I don't know, why it doesn't work. I did it with YT tutorial, but by the man it works.
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6
ApplicationWindow {
id: app_window
visible: true
width: 1024
height: 800
title: qsTr("Navigation")
PositionSource {
active: true
onPositionChanged: {
map_id.center = position.coordinate;
}
}
Rectangle {
id: mapRectangleID
width: 1024
height: 800
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
Map {
id: map_id
anchors.fill: parent
plugin: Plugin { name: "osm" }
center: QtPositioning.coordinate(51.320729390711975,12.280097007751465)
zoomLevel: 15
MapQuickItem {
//coordinate: QtPositioning.coordinate(59.91, 10.75)
sourceItem: Image {
id: endPointImage
source: "assets/marker.png"
width: 40.1
height: 34.3
} //size and position of maker
anchorPoint.x: endPointImage.width / 2
anchorPoint.y: endPointImage.height
} //marker
RouteModel {
id: routeBetweenPoints
plugin: Plugin { name: "osm" }
query: RouteQuery {id: routeQuery }
Component.onCompleted: {
routeQuery.addWaypoint(QtPositioning.coordinate(51.318784,12.2773504 ));
routeQuery.addWaypoint(QtPositioning.coordinate(51.3117764,12.280909000000065 ));
//routeQuery.addWaypoint(endPointGeaocodeModel)
update();
}
} //start and end point
MapItemView {
model: routeBetweenPoints
delegate: Component {
MapRoute {
route: routeData
line.color: "red"
line.width: 10
}
}
}//linie, die beide punkte verbindet
GeocodeModel{
id: endPointGeaocodeModel
plugin: Plugin { name: "osm" }
query: "Sandakerveien 116, Oslo"
onLocationsChanged: {
if (count)
endPointImage.coordinate = get(0).coordinate;
}
Component.onCompleted: update()
} //suche den platz mit strasse und stadt
Rectangle{
id:_ifStartPointLongitude
width: 100
height: 20
border.color: 'gray'
border.width: 2
x: 900
y: 120
anchors.left: app_window.right
TextInput {
id: txtPlainStartPointLongitude
anchors.fill: parent
anchors.margins: 4
}
}
} //all widgets and items of map
} //size and position of map
}
and This element doesn't work:
GeocodeModel{
id: endPointGeaocodeModel
plugin: Plugin { name: "osm" }
query: "Sandakerveien 116, Oslo"
onLocationsChanged: {
if (count)
endPointImage.coordinate = get(0).coordinate;
}
Component.onCompleted: update()
} //suche den platz mit strasse und stadt
I tried too another cities,streets, but it still doesn't work. Can someone explain me, what i did/wrote wrong?
The problem is caused because the item Image does not have the coordinate property, the one who has the coordinate property is the MapQuickItem, so we must set it to that item so we must give an id to the MapQuickItem, to observe the image we will establish the center of the map to the same coordinate.
// ...
MapQuickItem {
id: marker_id // <---
sourceItem: Image {
id: endPointImage
source: "assets/marker.png"
width: 100
height: 100
} //size and position of maker
anchorPoint.x: endPointImage.width / 2
anchorPoint.y: endPointImage.height
} //marker
// ...
GeocodeModel{
id: endPointGeaocodeModel
plugin: Plugin { name: "osm" }
query: "Sandakerveien 116, Oslo"
onLocationsChanged: {
if (count> 0){
marker_id.coordinate = get(0).coordinate // <----
map_id.center = get(0).coordinate // <----
}
}
Component.onCompleted: update()
} //suche den platz mit strasse und stadt
// ...

In 'AppListView' are empty places where Loader should load Component with 'SimpleRow'

I have a code application written in QT/QML and V-PLAY on the github here:
My problem:
I want to use AppListView to display different elements (like Button or SwitchApp) in 'Ustawienia' (Settings) page dependent on elements in array:
property var typeOfElementsInSettings: ['switch','switch','button','switch']
I use 'delegete: Loader' to do It, I inspired in this thread. I load component from other file, one will have Button inside, other AppSwitcher. Loader inserts SimpleRow to AppListView, I know It because variable myIndex should increment when SimpleRow is added and It was incremented but I can't see anything. I mean that I see empty space in place where should be displayed SimpleRow.
See screenshot:
Android Theme:
iOS Theme:
This is my code in Main.qml
NavigationItem{
title: "Ustawienia"
icon: IconType.cogs
NavigationStack{
Page{
title: "Ustawienia"
AppButton{
id: przy
text: "abba"
}
AppListView{
anchors.top: przy.bottom
model: ListModel{
ListElement{
type: "kategoria 1"; name: "opcja 1"
}
ListElement{
type: "kategoria 1"; name: "opcja 2"
}
ListElement{
type: "kategoria 2"; name: "opcja 3"
}
ListElement{
type: "Opcje programisty"; name: "Czyszczenie ustawień aplikacji"
}
}
section.property: "type";
section.delegate: SimpleSection {
title: section
}
delegate: Loader{
sourceComponent: {
switch(typeOfElementsInSettings[myIndex]){
case "switch":
console.log(typeOfElementsInSettings[myIndex])
console.log("s")
return imageDel;
case "button":
console.log(typeOfElementsInSettings[myIndex])
console.log("b")
return imageDel;
}
}
}
SimpleRowSwitch { id: imageDel }
VideoDelegate { id: videoDel }
}
}
}
onSelected: {
//console.log("selected")
}
Component.onCompleted: {
//console.log("Zrobiono")
}
}
This my code in SimpleRowSwitch.qml:
import VPlayApps 1.0
import QtQuick 2.9
Component{
SimpleRow {
x: 100
y: 200
text: name;
AppSwitch{
property int indexOfElementInSettings: 0
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: dp(10)
Component.onCompleted: {
indexOfElementInSettings=myIndex
console.log(myIndex)
if(switchsSettingsLogicArray[myIndex]===1){
checked=true
} else {
checked=false
}
//myIndex++;
}
onToggled: {
console.log(indexOfElementInSettings)
}
}
Component.onCompleted: {
console.log(x)
console.log(y)
console.log(typeOfElementsInSettings[myIndex])
console.log(myIndex)
myIndex++
}
onSelected: {
console.log("abba")
}
}
}

Resources