0
votes

I my test database, I have table named users, which represents loggable users. Now, I've succesfully connected to database through Qt/C++, exposed class to QML (also without problems), setup QML ListView to show this users with custom model and delegate (file main.qml) and when I run my app, five items are shown in ListView. Now, ListView's delegate is composed from Image and Text sections (Image section for loggable user image, which resides as BLOB in mysql database and Text section for user name, which also resides as VARCHAR in mysql database - both fields are in same table named users):

import QtQuick 2.3

Item
{
    id: uePeopleItemDelegate

    property Image uePersonImage
    property string uePersonName

    width: 256
    height: 256
    antialiasing: true

    clip: true

    Rectangle
    {
        id: ueRectangleMain
        color: "#000000"

        radius: 16
        anchors.fill: parent
        antialiasing: true
        border.color: "#ffffff"
        border.width: 4
        clip: true
        //opacity: 0.7

        Grid
        {
            antialiasing: true
            anchors.rightMargin: 12
            anchors.leftMargin: 12
            anchors.bottomMargin: 12
            anchors.topMargin: 12
            anchors.fill: parent
            spacing: 4
            rows: 2
            columns: 1
        }

        Row
        {
            id: ueRowImage
            anchors.rightMargin: 12
            anchors.leftMargin: 12
            anchors.bottom: parent.bottom
            anchors.right: parent.right
            anchors.left: parent.left
            anchors.top: parent.top
            anchors.bottomMargin: 48
            anchors.topMargin: 12
        }

        Image
        {
            id: uePersonleImage
            x: 12
            y: 12
            width: 232
            height: 196
            antialiasing: true
            fillMode: Image.PreserveAspectFit
            source: ""
        }

        Column
        {
            id: ueColumnPeopleInfo
            x: 12
            y: 214
            width: 232
            height: 30
            spacing: 0
        }

        Text
        {
            id: ueTextPersonName
            x: 12
            y: 214
            width: 232
            height: 30
            color: "#ffffff"
            text: uePersonName
            font.bold: true
            verticalAlignment: Text.AlignVCenter
            horizontalAlignment: Text.AlignHCenter
            font.pixelSize: 16
        }
    }
}

And here is screenshot of delegates: ListView delegates

If I delete/add user in database, the number of delegates changes according to number of table user records, which works perfect. But now I have two problems: In main.qml, I instantiate this ListView:

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtMultimedia 5.0
import QtQuick.Layouts 1.0
import QtTest 1.1

import "gui/delegates"

ApplicationWindow
{
    id: ueWindowMain

    title: qsTr("TestApp")

    width: Screen.desktopAvailableWidth
    height: Screen.desktopAvailableWidth

    visible: true

    opacity: 1.0

    contentOrientation: Qt.LandscapeOrientation

    color: "black"

    ListView
    {
        id: uePeopleListView
        snapMode: ListView.SnapToItem
        highlightRangeMode: ListView.ApplyRange
        anchors.right: parent.right
        anchors.rightMargin: 0
        anchors.bottom: parent.top
        anchors.bottomMargin: -128
        anchors.left: parent.left
        anchors.leftMargin: 0
        anchors.top: parent.top
        anchors.topMargin: 0
        orientation: ListView.Horizontal
        flickableDirection: Flickable.HorizontalFlick
        antialiasing: true
        spacing: 16
        delegate: UePeopleItemDelegate
        {
            id: uePersonDelegate

            uePersonImage: ""   // Q1: How do I retreive image (user image) from database?
            uePersonName: ""    // Q2: How do I retreive text (user name) from database?
        }
        model: uePeopleModel
    }
}

How do I retreive data (image and text) to show it in delegate in lines 49 and 50? Here are also header and implementation of my model class:

#ifndef UEPEOPLEMODEL_H
#define UEPEOPLEMODEL_H

#include <QImage>
#include <QVariant>
#include <QStringList>
#include <QDebug>
#include <QHash>
#include <QByteArray>
#include <QtSql/QSqlError>
#include <QtSql/QSqlQueryModel>
#include <QtSql/QSqlRecord>
#include <QModelIndex>

#include "../settings/uedefaults.h"

class UePeopleModel : public QSqlQueryModel
{
    Q_OBJECT

private:
    QHash<int, QByteArray> m_ueRoleNames;

    void ueGenerateRoleNames();

public:
    UePeopleModel(QObject *parent=0);
    ~UePeopleModel();

    QVariant data(const QModelIndex &index,
                  int role) const Q_DECL_OVERRIDE;
    void ueRefresh();
    inline QHash<int, QByteArray> ueRoleNames() const
        { return this->m_ueRoleNames; }
};

#endif // UEPEOPLEMODEL_H

and implementation:

#include "uepeoplemodel.h"

UePeopleModel::UePeopleModel(QObject* parent)
    : QSqlQueryModel(parent)
{
    QSqlDatabase db;

    if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
                                                 Qt::CaseInsensitive))
    {
            db=QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
                                         UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE);
    }   // if

    db.setHostName(/*this->uePosSettings()->ueDbHostname()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
    db.setDatabaseName(/*this->uePosSettings()->ueDbName()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
    db.setUserName(/*this->uePosSettings()->ueDbUser()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
    db.setPassword(/*this->uePosSettings()->ueDbPassword()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);

    if(db.open())
    {
        this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
                       db);
        this->ueGenerateRoleNames();
    }
    else
    {
        qDebug() << db.lastError().text();
    }
}   // default constructor

UePeopleModel::~UePeopleModel()
{
}   // default destructor

QVariant UePeopleModel::data(const QModelIndex &index,
                             int role) const
{
    QVariant value;

    if(role<Qt::UserRole)
    {
        value=QSqlQueryModel::data(index,
                                   role);
    }
    else
    {
        int iColumnIndex=role-Qt::UserRole-1;
        QModelIndex modelIndex=this->index(index.row(),
                                           iColumnIndex);

        value=QSqlQueryModel::data(modelIndex,
                                   Qt::DisplayRole);
    }   // if

    return value;

//    QVariant value=QSqlQueryModel::data(index,
//                                        role);

//    if(value.isValid()&&role==Qt::DisplayRole)
//    {
//        switch(index.column())
//        {
//            case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_ID:
//                return value.toInt();

//            case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_NAME:
//                return value.toString();

//            case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_APPPASSWORD:
//                return value.toString();

//            case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_CARD:
//                return value.toString();

//            case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_IMAGE:
//            {
//                QImage image;

//                image.loadFromData(value.toByteArray());

//                return image;
//            }   // case

//            default:
//                return value;
//        }   // switch
//    }   // if

//    return QVariant();
}   // data

void UePeopleModel::ueRefresh()
{
    this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE);
}   // ueRefresh

void UePeopleModel::ueGenerateRoleNames()
{
    this->ueRoleNames().clear();
    for(int iIndex=0; iIndex<this->record().count(); iIndex++)
    {
        this->ueRoleNames().insert(Qt::UserRole+1+iIndex,
                                   this->record().fieldName(iIndex).toUtf8());
    }   // for
}   // ueGenerateRoleNames
1

1 Answers

1
votes

The default QML image provider can only work with URLs or file paths. If you want to load a QML image from a C++ image class, such as QPixmap or QImage you will have to go about and implement your own image provider. I've described one possible implementation strategy here:

After that it is fairly straightforward, the data() method won't be returning an image wrapped in a QVariant, just a custom image URL targeted at the custom image provider, and that's what you are going to use in the QML delegate. Naturally, inside the database, you will still have a blob, and you will still use the fromData() method to construct the image, however the image provider will be used to associate the custom image source string to the actual image. Naturally, you must find a way to control the lifetime of the actual image so you don't get memory leaks. My suggestion is to implement something like the Pixmap item from the answer listed above, and make it a part of your delegate - this way the image will be deleted when no longer needed. You will however also need to implement setData() for the Pixmap and pass the QPixmap pointer in text form and store it in pix.

It might be easier and wiser to NOT store the image in the database, but as a regular file, and just store the relative path to it in the database, it will save you some trouble. As for the question "how to retrieve data" - I'd say go there and actually read the documentation...