I have a database with the coordinates of the airports and I need to display them with points on the map (QtLocation). With the QSqlQueryModel I can easily populate and show a TableView, but I have no idea how to create MapQuickItems.
class SqlModel : public QSqlQueryModel
{
Q_OBJECT
public:
enum Roles {
LatitudeRole = Qt::UserRole + 1,
LongitudeRole = Qt::UserRole + 2
};
explicit SqlModel(QObject *parent = nullptr) : QSqlQueryModel(parent) {}
QVariant data(const QModelIndex &index, int role) const override
{
int columnId = role - Qt::UserRole - 1;
QModelIndex modelIndex = this->index(index.row(), columnId);
return QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
}
protected:
QHash<int, QByteArray> roleNames() const override {
QHash<int, QByteArray> roles;
roles[LatitudeRole] = "latitude";
roles[LongitudeRole] = "longitude";
return roles;
}
};
in main.cpp:
//...
SqlModel *model = new SqlModel;
model->setQuery("SELECT air_latitude, air_longitude FROM tab_airports");
engine.rootContext()->setContextProperty("myModel", model);
//...
Using the SqlQueryModel of my previous answer that allows to obtain the data through the roles that have the same name of the fields and transforming it to QCoordinate using QtPositioning.coordinate in a MapItemView that is delegated to the MapQuickItem the following is obtained:
#include <QtGui>
#include <QtSql>
#include <QtQml>
class SqlQueryModel : public QSqlQueryModel {
Q_OBJECT
public:
using QSqlQueryModel::QSqlQueryModel;
QHash<int, QByteArray> roleNames() const {
QHash<int, QByteArray> roles;
for (int i = 0; i < record().count(); i++) {
roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
}
return roles;
}
QVariant data(const QModelIndex &index, int role) const {
QVariant value;
if (index.isValid()) {
if (role < Qt::UserRole) {
value = QSqlQueryModel::data(index, role);
} else {
int columnIdx = role - Qt::UserRole - 1;
QModelIndex modelIndex = this->index(index.row(), columnIdx);
value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
}
}
return value;
}
};
static bool createConnection(const QString &path) {
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
if (!db.open()) {
qDebug() << "Cannot open database\n"
"Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information how "
"to build it.\n\n"
"Click Cancel to exit.";
return false;
}
return true;
}
static void createData(){
QSqlQuery query;
query.exec("CREATE TABLE IF NOT EXISTS tab_airports(air_latitude REAL, air_longitude REAL)");
for(int i=0; i<10; i++){
query.prepare("INSERT INTO tab_airports(air_latitude, air_longitude) VALUES (?, ?)");
double lat = 59.91 + .02 * (QRandomGenerator::global()->generateDouble() - .5);
double lng = 10.75 + .02 * (QRandomGenerator::global()->generateDouble() - .5);
query.addBindValue(lat);
query.addBindValue(lng);
query.exec();
}
}
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
if (!createConnection(":memory:"))
return -1;
createData();
SqlQueryModel model;
model.setQuery("SELECT air_latitude, air_longitude FROM tab_airports");
engine.rootContext()->setContextProperty("airport_model", &model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtLocation 5.11
import QtPositioning 5.11
ApplicationWindow {
id: root
visible: true
width: 640
height: 480
Plugin {
id: mapPlugin
name: "osm"
}
Map {
id: map
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
MapItemView{
id: view
model: airport_model
delegate: MapQuickItem{
coordinate: QtPositioning.coordinate(model.air_latitude, model.air_longitude)
anchorPoint.x: image.width/2
anchorPoint.y: image.height
sourceItem: Image {
id: image
source: "http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_red.png"
}
}
}
}
}