qtqmlqtlocation

How to add items to the map from coordinates in the database?


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);
//...

Solution

  • 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"
                    }
                }
            }
        }
    }
    

    enter image description here