首页 > 解决方案 > 动态填充的组合框不显示文本,列表未定义

问题描述

我知道在 stackoverflow 和其他论坛上有很多关于从 C++ 动态填充组合框的不同问题,但是在所有这些问题中我找不到我需要的答案。目前我正在用 C++ 从我的数据库中获取一个列表并将其存储在我的CompanyList班级中。我的CompanyModel班级使用该班级并与我的 qml ui 进行通信。在我的 QML 编辑器中,我将模型设置为我想要从结构中获取的值CompanyModel.listtextRole

我面临的问题是我没有收到任何错误,但我的组合框仍然是空的。我找不到问题,所以我希望有人能看看我可能犯的错误。

我的公司结构

struct CompanyStruct {
    int id;
    QString name;
};

我的公司名单


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();
}

我的公司模式

#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();
}

我的 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);

我在 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
}

标签: c++qtqml

解决方案


通常,您将使用 C++ 创建模型并将它们公开给 QML。如果您从 QObject 派生演示数据,您甚至不必使用 qmlRegisterType。

为了简单起见,我只制作了除 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 方法,而是直接更新属性本身。


推荐阅读