KernelPanic
KernelPanic

Reputation: 2432

QML ListView.count returns 0, but delegates (Images) are seen in it

I have following QML ListView:

ListView
{
    antialiasing: true
    Layout.alignment: Qt.AlignCenter
    Layout.fillWidth: true

    Layout.preferredHeight: 128

    clip: true

    spacing: 64

    model: uePeopleModel

    orientation: ListView.Horizontal

    highlightFollowsCurrentItem: true

    delegate: Image
    {
        source: "image://uePeopleModel/"+model.ueRoleImage

        scale: parent.ListView.isCurrentItem ? 1.5 : 1

        Behavior on scale
        {
            NumberAnimation
            {
                duration: 200
            }   // NumberAnimation
        }   // Behavior
    }   // delegate

    preferredHighlightBegin: width/2
    preferredHighlightEnd: width /2
    highlightRangeMode: ListView.StrictlyEnforceRange
    Component.onCompleted:
    {
        currentIndex=count/2
        print("ListView.count: "+count)
        print("ListView.currentIndex: "+currentIndex)
        print("ListView.currentItem: "+currentItem)
    }   // Component.onCompleted
}   // ListView

Now, when I run app, the items (Images) are seen in ListView, but debug print statements report:

qml: ListView.count: 0 qml: ListView.currentIndex: 0 qml: ListView.currentItem: null

and therefore I cannot get "centered item". Why?! And items are neither scaled according to ListView's statement scale: parent.ListView.isCurrentItem ? 1.5 : 1, why?

Here is coresponding model header file:
#ifndef UEPEOPLEMODEL_H
#define UEPEOPLEMODEL_H

#include <QImage>
#include <QVariant>
#include <QStringList>
#include <QHash>
#include <QByteArray>
#include <QSqlError>
#include <QSqlQueryModel>
#include <QSqlRecord>
#include <QModelIndex>
#include <QQuickImageProvider>
#include <QByteArray>
#include <QSqlRecord>
#include <QSqlQuery>

#include "../settings/uedefaults.h"
#include "../core/uedatabaseconnectionstatus.h"
#include "../core/uetypes.h"
#include "../core/ueapplicationstatus.h"
#include "../core/ueuserrecord.h"

class UePeopleModel : public QSqlQueryModel,
                      public QQuickImageProvider
{
    Q_OBJECT

private:
    QSqlDatabase m_ueDb;

private:
    QSqlDatabase ueDatabase() const
        { return this->m_ueDb; }
    void ueSetDatabase(const QSqlDatabase& database)
        { this->m_ueDb=database; }
    QImage ueImage(const QString& id) const;

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

    QVariant data(const QModelIndex &index,
                  int role) const Q_DECL_OVERRIDE;
    QImage requestImage(const QString &id,
                        QSize *size,
                        const QSize &requestedSize);
    UeTypeRoles roleNames() const;
    void ueConnectToDatabase();
    UeTypeUsers* ueFetchUsers();

public:
    static const int ueRoleName=Qt::UserRole+1;
    static const int ueRoleImage=Qt::UserRole+2;
    static const int ueRolePassword=Qt::UserRole+3;

signals:
    void ueSignalDatabaseConnectionChanged(const UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus& newStatus);
};

#endif // UEPEOPLEMODEL_H

and here is it's implementation:

#include "uepeoplemodel.h"

UePeopleModel::UePeopleModel(QObject* parent)
    : QSqlQueryModel(parent),
      QQuickImageProvider(QQmlImageProviderBase::Image,
                          QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
    emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::NOT_CONNECTED);
}   // default constructor

UePeopleModel::~UePeopleModel()
{
    QString connName=this->ueDatabase().connectionName();

    this->ueDatabase().close();
    this->ueSetDatabase(QSqlDatabase());
    this->ueDatabase().removeDatabase(connName);

    emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::NOT_CONNECTED);
}   // default destructor

QVariant UePeopleModel::data(const QModelIndex &index,
                             int role) const
{
    switch(role)
    {
        case ueRoleImage:
        {
            return QString::number(index.row());
        } break;    // case

        case ueRoleName:
        {
            return this->record(index.row()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_NAME).toString();
        } break;    // case

        case ueRolePassword:
        {
            return this->record(index.row()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_APPPASSWORD).toString();
        } break;   // case

        default:
        {
            return QSqlQueryModel::data(index,
                                        role);
        } break;    // default
    }   // switch

    return QVariant();
}   // data

QImage UePeopleModel::ueImage(const QString &id) const
{
    return QImage::fromData(this->record(id.toInt()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_IMAGE).toByteArray(),
                            "PNG").scaled(UeDefaults::UeGraphics::PEOPLE_IMAGE_WIDTH,
                                          UeDefaults::UeGraphics::PEOPLE_IMAGE_HEIGHT,
                                          Qt::IgnoreAspectRatio,
                                          Qt::SmoothTransformation);
}   // ueImage

QImage UePeopleModel::requestImage(const QString &id,
                                   QSize *size,
                                   const QSize &requestedSize)
{
    Q_UNUSED(size)
    Q_UNUSED(requestedSize);

//    if(size)
//    {
//        *size=QSize(UeDefaults::UeGraphics::PEOPLE_IMAGE_WIDTH,
//                    UeDefaults::UeGraphics::PEOPLE_IMAGE_HEIGHT);
//    }   // if

    //return this->ueImage(id);

    return QImage::fromData(this->record(id.toInt()).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_IMAGE).toByteArray(),
                            "PNG").scaled(UeDefaults::UeGraphics::PEOPLE_IMAGE_WIDTH,
                                          UeDefaults::UeGraphics::PEOPLE_IMAGE_HEIGHT,
                                          Qt::IgnoreAspectRatio,
                                          Qt::SmoothTransformation);
}   // requestImage

UeTypeRoles UePeopleModel::roleNames() const
{
    UeTypeRoles roles;

    const int iRoleName=UePeopleModel::ueRoleName;
    const int iRoleImage=UePeopleModel::ueRoleImage;
    const int iRolePassword=UePeopleModel::ueRolePassword;

    roles.insert(iRoleName,
                 "ueRoleName");
    roles.insert(iRoleImage,
                 "ueRoleImage");
    roles.insert(iRolePassword,
                 "ueRolePassword");

    return roles;
}   // roleNames

void UePeopleModel::ueConnectToDatabase()
{
    if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
                                                 Qt::CaseInsensitive))
    {
        this->ueSetDatabase(QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
                                                      UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE));
    }   // if

    this->ueDatabase().setHostName(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
    this->ueDatabase().setDatabaseName(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
    this->ueDatabase().setUserName(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
    this->ueDatabase().setPassword(UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);

    if(this->ueDatabase().open())
    {
        this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
                       this->ueDatabase());
        emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::CONNECTED);
    }
    else
    {
        emit this->ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::NOT_CONNECTED);
    }   // if
}   // ueConnectToDatabase

UeTypeUsers* UePeopleModel::ueFetchUsers()
{
    UeTypeUsers* users=new UeTypeUsers();

    for(int iIndex=0; iIndex<this->record().count(); iIndex++)
    {
        users->append(new UeUserRecord(this,
                                       this->record(iIndex).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_ID).toString(),
                                       this->record(iIndex).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_NAME).toString(),
                                       this->record(iIndex).value(UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_APPPASSWORD).toString()));
    }   // for

    return users;
}   // ueFetchUsers

Is model ok?

According to user @Mido answer, I've reimplemented ListView as:

ListView
{
    id: ueUserInfoListView

    antialiasing: true
    Layout.alignment: Qt.AlignCenter
    Layout.fillWidth: true

    Layout.preferredHeight: 128

    clip: true

    spacing: 64

    model: uePeopleModel

    orientation: ListView.Horizontal

    highlightFollowsCurrentItem: false

    delegate: Image
    {
        id: ueUserInfoListViewDelegate

        source: "image://uePeopleModel/"+model.ueRoleImage

        opacity: 0.3

        function ueDoOpacity()
        {
            if(ueUserInfoListViewDelegate===parent.ListView.currentItem)
                opacity=1.0
            else
                opacity=0.3
            print(parent.ListView.currentIndex)
        }

        Behavior on opacity
        {
            NumberAnimation
            {
                duration: 300
            }   // NumberAnimation
        }   // Behavior

        Component.onCompleted:
        {
            ueUserInfoListViewDelegate.focusChanged.connect(ueDoOpacity)
        }   // Component.onCompleted
    }   // delegate

    Component.onCompleted:
    {
        preferredHighlightBegin: width/2
        preferredHighlightEnd: width /2
        highlightRangeMode: ListView.StrictlyEnforceRange
        currentIndex=count/2
    }   // Component.onCompleted
}   // ListView

I've also added print(parent.ListView.currentIndex) inside function ueDoOpacity and at program start I get:

qml: undefined

If I scroll left/right ListView's items, the function does not get called again. Why?!

And I've replaced target property scale with opacity, here is upgraded ListView:

        ListView
        {
            id: ueUserInfoListView

            antialiasing: true
            Layout.alignment: Qt.AlignCenter
            Layout.fillWidth: true

            Layout.preferredHeight: 128

            clip: true

            spacing: 64

            model: uePeopleModel

            orientation: ListView.Horizontal

            highlightFollowsCurrentItem: false

            delegate: Image
            {
                id: ueUserInfoListViewDelegate

                source: "image://uePeopleModel/"+model.ueRoleImage

                function ueDoOpacity()
                {
                    if(ueUserInfoListViewDelegate===currentItem)
                        opacity=1.0
                    else
                        opacity=0.3
                }

                Behavior on opacity
                {
                    NumberAnimation
                    {
                        duration: 1000
                    }   // NumberAnimation
                }   // Behavior

                Component.onCompleted:
                {
                    ueUserInfoListViewDelegate.focusChanged.connect(ueDoOpacity)
                }   // Component.onCompleted
            }   // delegate

            Component.onCompleted:
            {
                preferredHighlightBegin=width/2
                preferredHighlightEnd=width /2
                highlightRangeMode=ListView.StrictlyEnforceRange
                currentIndex=count/2
            }   // Component.onCompleted
        }   // ListView

Upvotes: 2

Views: 3903

Answers (1)

Mido
Mido

Reputation: 1112

I dont know why your scale is not changing, a workaround is to create a function doScale and connect it to focusChanged signal, try this example:

import QtQuick 2.0 
import QtQuick.Layouts 1.2
ListView
{
    id:idList
    antialiasing: true
    Layout.alignment: Qt.AlignCenter
    Layout.fillWidth: true
    width:200
    height:200
    Layout.preferredHeight: 128

    clip: true

    spacing: 10

    model: 3

    orientation: ListView.Horizontal

    highlightFollowsCurrentItem: true

    delegate: Rectangle
    {
    id:obj
    // source: "image://uePeopleModel/"+model.ueRoleImage
    color:"yellow"
    width:30
    height:30

    function doScale()
    {
        if(obj === idList.currentItem)
            obj.scale = 1.5
        else
            obj.scale = 1.0
    }
    //scale: parent.ListView.isCurrentItem ? 1.5 : 1
    Component.onCompleted:
    {
        obj.focusChanged.connect(doScale)
    }
    Behavior on scale
    {
        NumberAnimation
        {
            duration: 300
        }   // NumberAnimation
    }   // Behavior
}   // delegate

preferredHighlightBegin: width/2
preferredHighlightEnd: width /2
highlightRangeMode: ListView.StrictlyEnforceRange
Component.onCompleted:
{
    currentIndex=count/2
    print("ListView.count: "+count)
    print("ListView.currentIndex: "+currentIndex)
    print("ListView.currentItem: "+currentItem)
}   // Component.onCompleted
} 

Upvotes: 1

Related Questions