Поле со списком с динамическим заполнением, не отображается текст, список не определен - PullRequest
0 голосов
/ 26 мая 2020

Я знаю, что есть много разных вопросов о stackoverflow и других форумах о динамическом заполнении поля со списком из C ++, но из всех этих вопросов я не могу найти ответ, который мне нужен. В настоящее время я беру список из своей базы данных на C ++ и сохраняю его в своем классе CompanyList. Мой CompanyModel класс использует этот класс и взаимодействует с моим qml ui. В моем редакторе QML я установил модель на CompanyModel.list, а textRole на значение, которое я хочу от структуры.

Проблема, с которой я столкнулся, заключается в том, что я не получаю никаких ошибок, но мое поле со списком все еще пусто. Я не могу найти проблему, поэтому надеюсь, что кто-то сможет найти ошибку, которую я мог сделать.

My Company Struct

struct CompanyStruct {
    int id;
    QString name;
};

My Company List


CompanyList::CompanyList(QObject *parent) : QObject(parent)
{
    appendItem({-1, "test company"});
    appendItem({-2, "test company 2"});
}

QVector<CompanyStruct> CompanyList::items() const
{
    return mItems;
}

bool CompanyList::setItemAt(int index, const CompanyStruct &item)
{
    if (index < 0 || index >= mItems.size())
        return false;

    const CompanyStruct &oldItem = mItems.at(index);
    if (item.id == oldItem.id && item.name == oldItem.name)
        return false;

    mItems[index] = item;
    return true;
}

void CompanyList::appendItem()
{
    emit preItemAppended();

    CompanyStruct company;
    company.id = -1;
    company.name = "This is a test company!";
    mItems.append(company);

    emit postItemAppended();
}

void CompanyList::appendItem(CompanyStruct item)
{
    emit preItemAppended();

    mItems.append(item);

    emit postItemAppended();
}

My Модель компании

#include "companymodel.h"

#include "companylist.h"

CompanyModel::CompanyModel(QObject *parent)
    : QAbstractListModel(parent)
    , mList(nullptr)
{
}

int CompanyModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid() || !mList)
        return 0;

    return mList->items().size();
}

QVariant CompanyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || !mList)
        return QVariant();

    const CompanyStruct item = mList->items().at(index.row());
    switch (role) {
        case IdRole:
            return QVariant(item.id);
        case NameRole:
            return QVariant(item.name);
    }

    return QVariant();
}

bool CompanyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!mList)
        return false;

    CompanyStruct item = mList->items().at(index.row());
    switch (role) {
        case IdRole:
            item.id = value.toInt();
        break;
        case NameRole:
            item.name = value.toString();
        break;
    }

    if (mList->setItemAt(index.row(), item)) {
        emit dataChanged(index, index, QVector<int>() << role);
        return true;
    }
    return false;
}

Qt::ItemFlags CompanyModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::NoItemFlags;

    return Qt::ItemIsSelectable;
}

QHash<int, QByteArray> CompanyModel::roleNames() const
{
    QHash<int, QByteArray> names;
    names[IdRole] = "id";
    names[NameRole] = "name";
    return names;
}

CompanyList *CompanyModel::list() const
{
    return mList;
}

void CompanyModel::setList(CompanyList *list)
{
    beginResetModel();

    if (mList)
        mList->disconnect(this);

    mList = list;

    if (mList) {
        connect(mList, &CompanyList::preItemAppended, this, [=]() {
            const int index = mList->items().size();
            beginInsertRows(QModelIndex(), index, index);
        });

        connect(mList, &CompanyList::postItemAppended, this, [=]() {
            endInsertRows();
        });
    }

    endResetModel();
}

My Main. cpp

qmlRegisterType<CompanyModel>("Company", 1,0, "CompanyModel");
qmlRegisterUncreatableType<CompanyList>("Company", 1,0, "CompanyList", "CompanyList should not be created in QML");

CompanyList companyList;

QQmlApplicationEngine engine;

engine.rootContext()->setContextProperty("companyList", &companyList);

My combobox в QML


import Company 1.0


ComboBox {
    Layout.column: 1
    Layout.columnSpan: 3
    Layout.row: 4
    id: cbSelectKlant
    implicitWidth: parent.width*0.6
    implicitHeight: parent.height*0.05

    background: Rectangle {
        color: "white"
        border.color: "#6abc93"
        border.width: 3
        width: parent.width
        height: parent.height
    }
    textRole: "name"
    model: CompanyModel.list
}

Ответы [ 2 ]

0 голосов
/ 28 мая 2020

Обычно вы создаете свои модели на C ++ и предоставляете их QML. Вам даже не нужно использовать qmlRegisterType, если вы получаете данные своей презентации из QObject.

Для простоты я сделал код только для заголовка, кроме main. cpp

//company.h file:

#ifndef COMPANY_H
#define COMPANY_H

#include <QObject>

class Company : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int id READ id WRITE setId CONSTANT)
    Q_PROPERTY(QString name READ name WRITE setName CONSTANT)
    Q_PROPERTY(QString displayName READ displayName CONSTANT)
public:
    Company(QObject *parent=nullptr) : QObject(parent)
    {}

    int id() const { return mID; }
    void setId(const int id) { mID = id; }

    QString name() const { return mName; }
    void setName(const QString& name) { mName = name; }

    QString displayName() { return "Company: " + mName + ", ID: " + QString::number(mID); }
private:
    int mID;
    QString mName;
};

#endif // COMPANY_H
//companylistmodel.h file:

#ifndef COMPANYLISTMODEL_H
#define COMPANYLISTMODEL_H

#include "company.h"
#include <QAbstractListModel>
#include <vector>

class CompanyListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    enum Roles
    {
        CompanyRole = Qt::UserRole
    };

    CompanyListModel(QObject* parent = nullptr) : QAbstractListModel(parent)
    {
        mCompanies.push_back(new Company(this));
        mCompanies.back()->setName("Google"); mCompanies.back()->setId(1);
        mCompanies.push_back(new Company(this));
        mCompanies.back()->setName("Microsoft"); mCompanies.back()->setId(2);
        mCompanies.push_back(new Company(this));
        mCompanies.back()->setName("CraftUnique"); mCompanies.back()->setId(3);
    }

    int rowCount(const QModelIndex& parent = QModelIndex()) const override { return mCompanies.size(); }
    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override { return QVariant::fromValue(mCompanies.at(index.row())); }
    bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override { return true; } // use property instead
    virtual QHash<int, QByteArray> roleNames() const override
    {
        QHash<int, QByteArray> names;
        names[CompanyRole] = "companyRole";
        return names;
    }

private:
    std::vector<Company*> mCompanies;
};

#endif // COMPANYLISTMODEL_H
// main.cpp file:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QQmlContext>
#include "companylistmodel.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQuickView view;
    CompanyListModel clm;
    view.rootContext()->setContextProperty("clm", &clm);
    view.setSource(QStringLiteral("qrc:/main.qml"));
    view.show();
    return app.exec();
}
//main.qml file:

import QtQuick 2.12
import QtQuick.Controls 2.12

Rectangle {
    anchors.fill: parent
    color: "white"
    Component.onCompleted: { console.log(clm) }
    ComboBox {
        id: cbSelectKlant

        implicitWidth: parent.width
        implicitHeight: 30

        model: clm
        textRole: "companyRole.displayName"

        contentItem: Label {
            anchors.fill: parent
            verticalAlignment: Text.AlignVCenter
            text: cbSelectKlant.currentText
        }

        background: Rectangle {
            color: "gray"
        }

        delegate: ItemDelegate {
            implicitWidth: parent.width
            implicitHeight: 30
            contentItem: Label {
                anchors.fill: parent
                verticalAlignment: Text.AlignVCenter
                text: companyRole.name + " (" + companyRole.id + ")"
            }
        }
    }
}

Вы даже можете назначать значения из QML, например: companyRole.name = "SomeCompany" И это не вызовет метод setData вашей модели, а напрямую обновит само свойство.

0 голосов
/ 27 мая 2020

Первая часть проблемы заключается в том, что вы не инициализируете mList в приведенном коде (который, я думаю, немного короче MRE ).

Измените конструктор на следующее:

CompanyModel::CompanyModel(QObject *parent)
    : QAbstractListModel(parent)
    , mList(new CompanyList(this))
{
}

И вы также позволяете qml-разработчику создать экземпляр CompanyModel в QML (первая строка файла main. cpp), что вы как бы делаете, но не на самом деле (последняя строка кода ComboBox QML). Таким образом, экземпляр CompanyModel не создается, но вы все еще пытаетесь получить свойство list из определения класса, которое будет неопределенным (II C), что приведет к пустому ComboBox без ошибок.

Это можно решить, создав его экземпляр в QML:

import Company 1.0


ComboBox {
    Layout.column: 1
    Layout.columnSpan: 3
    Layout.row: 4
    id: cbSelectKlant
    implicitWidth: parent.width*0.6
    implicitHeight: parent.height*0.05

    background: Rectangle {
        color: "white"
        border.color: "#6abc93"
        border.width: 3
        width: parent.width
        height: parent.height
    }
    textRole: "name"
    model: theModel.list

    CompanyModel {
        id: theModel
    }

}

Однако я сомневаюсь, что это именно то, что вам нужно, поскольку вы не сможете управлять theModel из C ++. Вероятно, поэтому вы устанавливаете свойство rootContext, но фактически не используете его (последняя строка main. cpp).

Итак, измените QML на это:

import Company 1.0


ComboBox {
    Layout.column: 1
    Layout.columnSpan: 3
    Layout.row: 4
    id: cbSelectKlant
    implicitWidth: parent.width*0.6
    implicitHeight: parent.height*0.05

    background: Rectangle {
        color: "white"
        border.color: "#6abc93"
        border.width: 3
        width: parent.width
        height: parent.height
    }
    textRole: "name"
    model: companyList.list
}

В качестве последнего совета также измените первую строку main. cpp на:

qmlRegisterUncreatableType<CompanyModel>("Company", 1,0, "CompanyModel", "CompanyModel should not be created in QML");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...