简体   繁体   English

用什么代替QStringList?

[英]What to use instead of QStringList?

I'm new to Qt, so I'm not sure what to use. 我是Qt的新手,所以不确定使用什么。

I thought I would have a QStringList to give to my QStringListModel and display it in a ListView . 我以为我会有一个QStringList交给我的QStringListModel并显示在ListView

Now, however, I need to divide QStringList in the values of 2 types. 但是,现在,我需要将QStringList分为2种类型的值。 So, I need to have string + some typeId, not just one string, but QStringList is for one-dimensional list only. 因此,我需要具有字符串+一些typeId,而不仅仅是一个字符串,而且QStringList仅用于一维列表。

Anyone could give an advice on what is the best way to try to implement this? 任何人都可以就实现此目标的最佳方法提出建议?

The solution is to use QAbstractListModel subclass as a Qt Quick model. 解决方案是将QAbstractListModel子类用作Qt Quick模型。 An example of base class for a models (I use it for convenience): 模型的基类示例(为方便起见,我将其使用):

// abstractobjectlistmodel.h
#pragma once

#include <QtCore>

struct AbstractObjectListModel
        : public QAbstractListModel
{

    explicit AbstractObjectListModel(QObject * const parent = Q_NULLPTR)
        : QAbstractListModel{parent}
    { ; }

    int rowCount(QModelIndex const & parent = {}) const Q_DECL_OVERRIDE Q_DECL_FINAL
    {
        Q_UNUSED(parent);
        return items.count();
    }

    QVariant data(QModelIndex const & index, const int role = Qt::DisplayRole) const Q_DECL_OVERRIDE Q_DECL_FINAL
    {
        if (!index.isValid()) {
            return {};
        }
        switch (role) {
        case Qt::UserRole : {
            return QVariant::fromValue(items[index.row()].data());
        }
        default : {
            return {};
        }
        }
    }

    QHash< int, QByteArray > roleNames() const Q_DECL_OVERRIDE Q_DECL_FINAL
    {
        auto roleNames = QAbstractListModel::roleNames();
        roleNames.insert(Qt::UserRole, "modelData");
        return roleNames;
    }

    Q_INVOKABLE
    virtual
    QObject * get(int row) const
    {
        if (row < 0) {
            return {};
        }
        if (row >= rowCount()) {
            return {};
        }
        return items[row];
    }

    void remove(int row, int count = 1)
    {
        Q_ASSERT(count > 0);
        Q_ASSERT(row >= 0);
        Q_ASSERT(row + count <= rowCount());
        beginRemoveRows({}, row, row + count - 1);
        while (0 < count) {
            items.takeAt(row)->deleteLater();
            --count;
        }
        endRemoveRows();
    }

    void clear()
    {
        if (!items.isEmpty()) {
            remove(0, rowCount());
        }
    }

protected :

    ~AbstractObjectListModel() Q_DECL_OVERRIDE Q_DECL_EQ_DEFAULT; // derived classes should not meant to be manipulated polymorphically

    QList< QPointer< QObject > > items;

    void insert(int row, QObject * const item)
    {
        item->setParent(this);
        beginInsertRows({}, row, row);
        items.insert(row, item);
        endInsertRows();
    }

    void append(QObject * const item)
    {
        insert(rowCount(), item);
    }

};

But one need to override get to access items' Q_PROPERTY properties (in addition to dynamic ones): 但是需要覆盖get访问项的Q_PROPERTY属性(除了动态属性之外):

// type of element
class Project
        : public QObject
{

    Q_OBJECT

    Q_PROPERTY(QString name MEMBER name NOTIFY nameChanged)
    Q_PROPERTY(QString path MEMBER path NOTIFY pathChanged)

public :

    Project(QString name, QString path,
            QObject * const parent = Q_NULLPTR)
        : QObject{parent}
        , name{name}
        , path{path}
    { ; }

Q_SIGNALS :

    void nameChanged(QString name);
    void pathChanged(QString path);

private :

    QString name;
    QString path;

};

// custom model
class ProjectsListModel
        : public AbstractObjectListModel
{

    Q_OBJECT

public :

    explicit ProjectsListModel(QObject * const parent = Q_NULLPTR)
        : AbstractObjectListModel{parent}
    { ; }

    void appendProject(QString name, QString path)
    {
        AbstractObjectListModel::append(::new Project{name, path});
    }

    Q_INVOKABLE
    Project *
    get(int row) const Q_DECL_OVERRIDE
    {
        return qobject_cast< Project * >(AbstractObjectListModel::get(row));
    }

};

Before use one need to register concrete model with qmlRegisterType< ProjectsListModel >(); 使用之前,需要使用qmlRegisterType< ProjectsListModel >();注册具体模型qmlRegisterType< ProjectsListModel >(); . Properties of Project class are avaliable in delegate and highlight by means of members of modelData . Project类的属性在delegate中可用,并通过modelData的成员highlight

Another example: 另一个例子:

struct TimeZoneModel Q_DECL_FINAL
        : public QAbstractListModel
{

    Q_OBJECT

public :

    explicit TimeZoneModel(QObject * const parent = Q_NULLPTR)
        : QAbstractListModel{parent}
    { ; }

    int rowCount(QModelIndex const & parent = {}) const Q_DECL_OVERRIDE
    {
        Q_UNUSED(parent);
        return timeZoneIds.count();
    }

    QVariant data(QModelIndex const & index, const int role = Qt::DisplayRole) const Q_DECL_OVERRIDE
    {
        if (!index.isValid() || (role > Qt::UserRole + 4)) {
            return {};
        }
        QTimeZone timeZone{timeZoneIds[index.row()]};
        if (!timeZone.isValid()) {
            return {};
        }
        return roleData(timeZone, role);
    }

    QHash< int, QByteArray > roleNames() const Q_DECL_OVERRIDE
    {
        auto roleNames = QAbstractListModel::roleNames();
        int i = Qt::UserRole;
        for (const auto role : {"modelData", "id", "comment", "name", "country"}) {
            roleNames.insert(i++, role);
        }
        return roleNames;
    }

    Q_INVOKABLE
    QByteArray get(int row) const
    {
        if (row < 0) {
            return {};
        }
        if (row >= rowCount()) {
            return {};
        }
        return timeZoneIds[row];
    }

private :

    QVariant roleData(QTimeZone const & timeZone, int role = Qt::UserRole) const
    {
        switch (role) {
        case Qt::UserRole : {
            QVariantMap modelData;
            const auto names = roleNames();
            while (++role < Qt::UserRole + 5) {
                modelData.insert(QString::fromUtf8(names[role]), roleData(timeZone, role));
            }
            return modelData;
        }
        case Qt::UserRole + 1: {
            return QString::fromUtf8(timeZone.id());
        }
        case Qt::UserRole + 2 : {
            return timeZone.comment();
        }
        case Qt::UserRole + 3 : {
            return timeZone.displayName(QTimeZone::StandardTime);
        }
        case Qt::UserRole + 4 : {
            return QLocale::countryToString(timeZone.country());
        }
        default : {
            return {};
        }
        }
    }

    const QByteArrayList timeZoneIds = QTimeZone::availableTimeZoneIds();

};

In addition to access via modelData 's fields ( modelData.id , modelData.comment etc) all the symbols are accessible directly (ie id , comment etc) in delegate and highlight contexts of the ListView . 除了通过modelData的字段( modelData.idmodelData.comment等)访问modelData.id ,还可以在ListView delegatehighlight上下文中直接访问所有符号(即idcomment等)。

Model TimeZoneModel is const and can be injected into global scope directly without any performance drawbacks: Model TimeZoneModelconst ,可以直接注入全局范围,而不会产生任何性能缺陷:

QQmlApplicationEngine engine;

TimeZoneModel timeZoneModel;
Q_SET_OBJECT_NAME(timeZoneModel);
qmlRegisterType< TimeZoneModel >();
const auto rootContext = engine.rootContext();
rootContext->setContextProperty(timeZoneModel.objectName(), &timeZoneModel);

If you need dictionary that contains QString and any other type I suggest you to use 如果您需要包含QString和任何其他类型的字典,我建议您使用

  QMap<QString, YourType> myMap;

Here you have some example of usage: 这里有一些用法示例:

QMap<int, QString> myMap;
myMap.insert(1,"A");
myMap.insert(2,"B");
myMap[3] = "C";

foreach(int i, myMap.keys()) qDebug() << myMap[i];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM