Как установить модель C ++ через родительские компоненты в qml? - PullRequest
0 голосов
/ 13 марта 2020

У меня есть:

  1. класс модели c ++ ( Банк ) для хранения простых объектов данных ( Коэффициент ):
typedef quint32 Coefficient;

class Bank : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<Coefficient> coefficients READ coefficients WRITE setCoefficients NOTIFY coefficientsChanged)

public:
    explicit Bank(QList<Coefficient> coefficients = QList<Coefficient>(), QObject *parent = nullptr);

    QList<Coefficient> coefficients() const;
    void setCoefficients(QList<Coefficient> coefficients);

    // ...

signals:
    void coefficientsChanged(QList<Coefficient> coefficients);

private:
    QList<Coefficient> _coefficients;
};
класс AbstractListModel ( BankClass ) для работы с представлениями через данные:
class Bank;

class BankModel : public QAbstractListModel
{
    Q_OBJECT
    Q_PROPERTY(Bank* bank READ bank WRITE setBank)

public:
    enum {
        CoefficientRole = Qt::UserRole
    };

    explicit BankModel(QObject *parent = nullptr);

    int rowCount(const QModelIndex &parent = QModelIndex()) const override;

    QVariant data(const QModelIndex &index, int role = CoefficientRole) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    Qt::ItemFlags flags(const QModelIndex& index) const override;
    QHash<int, QByteArray> roleNames() const override;

    Bank* bank() const;
    void setBank(Bank* bank);

private:
    Bank* _bank;
};
модель на основе QObjectList для хранения нескольких моделей AbstractListModel ( BankModel )
class CoefficientListModel;

class ConfigModel : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject*> banks READ banks WRITE setBanks NOTIFY banksChanged)

public:
    explicit ConfigModel(QList<QObject*> banks = QList<QObject*>(), QObject *parent = nullptr);

    QList<QObject*> banks() const;
    void setBanks(QList<QObject*> banks);

signals:
    void banksChanged(QList<QObject*> banks);

private:
    QList<QObject*> _banks;
};
и представление qml, чтобы настроить все это (main.qml):
Window {
    // ...
    ListView {
        // ...
        model: cfg // ConfigModel
        delegate: ConfigDelegate {
            // ...
            ListView {
                model: model.bank // BankModel
                delegate: BankDelegate {
                    some int property: coefficient // my role in bank model
                }
            }
        }
    }
}

, где cfg - это зарегистрированное в main. cpp object:

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qmlRegisterType<CoefficientListModel>("Config", 1, 0, "CoefficientListModel");
    qmlRegisterType<ConfigModel>("Config", 1, 0, "ConfigModel");

    ConfigModel cfg;
    cfg.setBanks(QList<QObject*>()
                 << new CoefficientListModel(QList<Coefficient>({ Coefficient { 11 }, Coefficient { 21 }, Coefficient { 31 }, Coefficient { 41 } }))
                 // ...
                 << new CoefficientListModel(QList<Coefficient>({ Coefficient { 15 }, Coefficient { 25 }, Coefficient { 35 }, Coefficient { 45 } }))
                 );

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty(QStringLiteral("cfg"), &cfg);
    engine.rootContext()->setContextProperty(QStringLiteral("client"), &client);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

Итак, как установить модели c ++ в этой глубине qml от верхнего уровня? Или что здесь не так? Это правильная архитектура приложения?

Это должно выглядеть, как на рисунке ниже. enter image description here

Редактировать:

Теперь у меня есть класс в виде элемента дерева:

class CoefficientItem
{
public:
    CoefficientItem(quint32 value = -1, int row = 0, CoefficientItem* parent = nullptr);
    ~CoefficientItem();

    CoefficientItem *childAt(int i);
    int childrenCount();
    CoefficientItem *parent();
    quint32 value() const;
    int row() const;

    void setValue(const quint32& value);
    void setParent(CoefficientItem* parent_item);

    void appendChild(CoefficientItem* child);

private:
    quint32 _value;
    CoefficientItem* _parent_item;
    QHash<int, CoefficientItem*> _child_items;
    int _row_number;
};

и модель дерева:

class ConfigModel : public QAbstractItemModel
{
    Q_OBJECT

    enum { CoefficientRole = Qt::UserRole };

public:
    explicit ConfigModel(const QVector<QVector<quint32>>& config, CoefficientItem* root = nullptr, QObject *parent = nullptr);
    ~ConfigModel();

    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex parent(const QModelIndex &index) const override;

    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;

    QVariant data(const QModelIndex &index, int role = CoefficientRole) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    Qt::ItemFlags flags(const QModelIndex& index) const override;

    void setModelUp(const QVector<QVector<quint32> >& config);

private:
    CoefficientItem* _root_item;
};

И проблема теперь заключается в доступе к внутреннему уровню модели дерева. В main.qml у меня есть представление списка:

ListView {
    anchors.fill: parent
    model: DelegateModel {
        model: cfg
        delegate: BankView {}
    }
}

BankView.qml - делегат, состоящий из BankViewHeader.qml ( как флажок) и BankViewDescription.qml (как компонент со списком текстовых полей)

BankView.qml :

Rectangle {
    id: bank_view
    width: parent.width
    height: bank_view_column.height
    color: "#946782"

    Column {
        id: bank_view_column
        spacing: 0
        clip: true

        BankViewHeader {
            id: checker
            text: qsTr("Bank " + model.index)
            checked: true
            implicitWidth: bank_view.width
        }

        BankViewDescription {
            id: description
            isOpened: checker.checked
            width: bank_view.width
        }
    }

    Component.onCompleted: checker.checked = false
}

BankViewDescription.qml :

RowLayout {
    // ...
    ListView {
        model: DelegateModel {
            model: model // <-- problem here ???
            delegate: Row {
                TextField {
                    //... use my role here - coefficient (uint32)
                }
            }
            // ...
        }
        // ...
    }
}

Так что не так? нет ошибок в журнале, и верхний уровень дерева работает нормально (я думаю), представление показывает 4 банка, которые были инициализированы в main. cpp.

enter image description here

1 Ответ

0 голосов
/ 20 марта 2020

Итак, рассмотрим редактирование части, и с помощью Amfasis решение: для этой структуры (двумерное хранение данных, как на картинке) мы должны создать древовидную модель, и после этого мы должны установить правильную структуру qml.

Структура qml в моем случае:

// model view in main.qml
ListView {
    // ...
    model: DelegateModel {
        id: bank_list_model
        model: cfg // my ConfigModel
        delegate: BankView {
            bankIndex: bank_list_model.modelIndex(index)
        }
    }
}

BankView.qml:

Rectangle {  // your any item
    property alias bankIndex: description.bankIndex

    // ...

    BankViewDescription {
        id: description
        // ...
    } 
}

BankViewDescription.qml:

RowLayout {  // your any item
    property alias bankIndex: regs_list_model.rootIndex

    // ...

    ListView {
        model: DelegateModel {
            id: regs_list_model
            model: cfg
            delegate: Row {
                TextField {
                    text: coefficient // use your role
                }
            }
        }
    }
}

Итак, здесь мы link Свойство rootIndex DelegateModel через наши элементы с псевдонимами.

PS: я забыл переопределить метод roleNames в ConfigModel при редактировании.

PPS: Если вам известен более простой способ описания модели, просмотрите соединение или структуру приложения, пожалуйста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...