Обновление QML TableView после нажатия кнопки через C ++ - PullRequest
1 голос
/ 22 апреля 2019

Я хочу добавить в просмотр таблицы QML определенное количество строк, нажав кнопку. Пользовательский интерфейс выглядит так:

enter image description here

После нажатия «Обновить модель списка» в TableView должна появиться новая строка.

Мой код выглядит следующим образом (ниже). Я полагаю, что метод addPerson должен выдать событие dataChanged , чтобы это работало. Как я могу это сделать? Или есть лучшее решение для синхронизации табличного представления QML с моделью C ++?

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include "MainWindow.h"
int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);

    qmlRegisterType<TableModel>("TableModel", 0, 1, "TableModel");

    QQmlApplicationEngine engine;
    MainWindow mainWindow;

    return app.exec();
}

mainwindow.h

#pragma once

#include <QQmlApplicationEngine>
#include <QtQuick>

#include "TableModel.h"

class MainWindow : public QObject {
    Q_OBJECT;

public:
    explicit MainWindow() {
        engine_.load(QUrl(QStringLiteral("qrc:/main.qml")));

        QObject *rootObject = engine_.rootObjects().first();
        QObject::connect(rootObject, SIGNAL(on_ButtonUpdateListModel_click()), this, SLOT(on_ButtonUpdateListModel_click()));
    }

public slots:

    void on_ButtonUpdateListModel_click() {         
        QQuickView view;
        QQmlContext *ctxt = view.rootContext();
        model_.addPerson();
        ctxt->setContextProperty("myModel", &model_);
    }

private:
    TableModel model_;
    QQmlApplicationEngine engine_;
};

tablemodel.h

#pragma once

#include <QAbstractTableModel>
#include <QObject>

class TableModel : public QAbstractTableModel {
    Q_OBJECT;
    enum TableRoles { TableDataRole = Qt::UserRole + 1, HeadingRole };

public:
    explicit TableModel(QObject *parent = nullptr) : QAbstractTableModel(parent) {
        table.append({
          "First Name",
          "Last Name",
          "Age",
        });
    }

    int rowCount(const QModelIndex & = QModelIndex()) const override {
        return table.size();
    }

    int columnCount(const QModelIndex & = QModelIndex()) const override {
        return table.at(0).size();
    }

    QVariant data(const QModelIndex &index, int role) const override {
        switch (role) {
        case TableDataRole: {
            return table.at(index.row()).at(index.column());
        }
        case HeadingRole: {
            if (index.row() == 0) {
                return true;
            } else {
                return false;
            }
        }
        default: break;
        }

        return QVariant();
    }

    QHash<int, QByteArray> roleNames() const override {
        QHash<int, QByteArray> roles;
        roles[TableDataRole] = "tabledata";
        roles[HeadingRole] = "heading";
        return roles;
    }

    void addPerson() {
        table.append({
          "Marc",
          "Fonz",
          "25",
        });
        int idx = table.size() - 1;
        emit dataChanged(index(idx), index(idx));
    }

private:
    QVector<QVector<QString>> table;
}; 

main.qml

import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

import Qt.labs.settings 1.0
import Qt.labs.platform 1.0 as Platform

import QtQuick.Controls.Material 2.12
import TableModel 0.1

ApplicationWindow {
    id: window
    visible: true
    width: 1040
    height: 480

    signal on_ButtonUpdateListModel_click()

    ColumnLayout{
        spacing: 2
        anchors.fill: parent
        Button {
            text: qsTr("Update List Model")
            onClicked: on_ButtonUpdateListModel_click()
        }

        TableModel {
            id: myModel
        }
        TableView {
            width: 400
            height: 200
            columnSpacing: 1
            rowSpacing: 1
            clip: true

            ScrollIndicator.horizontal: ScrollIndicator { }
            ScrollIndicator.vertical: ScrollIndicator { }

            model: myModel


            delegate: Rectangle {
                implicitWidth: 100
                implicitHeight: 20
                border.color: "black"
                border.width: 2
                color: (heading==true) ? 'teal':"green"

                TableView.onPooled: console.log(tabledata + " pooled")
                TableView.onReused: console.log(tabledata + " resused")

                Text {
                    text: tabledata
                    font.pointSize: 10
                    anchors.centerIn: parent
                }
            }
        }

    }
}

1 Ответ

2 голосов
/ 22 апреля 2019

У вас есть следующие ошибки:

  • В addPerson вы добавляете строку, поэтому вы не должны использовать dataChanged, поскольку этот сигнал указывает, что что-то, что уже существует, было изменено, вместо этого вы должны использоватьbeginInsertRows () и endInsertRows ().

  • TableModel, созданный в MainWindow, отличается от TableModel, созданного в QML.

  • Вам не нужно создаватьQQmlApplicationEngine в main.cpp, так как вам нужно использовать только одно в MainWindow.

  • Вы должны отделить бизнес-логику от представления, поэтому считается плохой практикой экспортировать объекты из QML вC ++.

Учитывая вышеизложенное, решение состоит в следующем:

  • Сделайте метод addPerson Q_INVOKABLE, чтобы он был доступен в QML.

  • Экспорт TableModel при запуске в QML с использованием setContextProperty, поэтому нет необходимости регистрировать TableModel.

main.cpp

#include "MainWindow.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    MainWindow mainwindow;
    return app.exec();
}

TableModel.h

#pragma once

#include <QAbstractTableModel>
#include <QObject>

class TableModel : public QAbstractTableModel {
    Q_OBJECT
    enum TableRoles { TableDataRole = Qt::UserRole + 1, HeadingRole };
public:
    explicit TableModel(QObject *parent = nullptr) : QAbstractTableModel(parent) {
        table.append({
                         "First Name",
                         "Last Name",
                         "Age",
                     });
    }
    int rowCount(const QModelIndex & = QModelIndex()) const override {
        return table.size();
    }

    int columnCount(const QModelIndex & = QModelIndex()) const override {
        return table.at(0).size();
    }

    QVariant data(const QModelIndex &index, int role) const override {
        switch (role) {
        case TableDataRole: {
            return table.at(index.row()).at(index.column());
        }
        case HeadingRole: {
            return index.row() == 0;
        }
        default: break;
        }
        return QVariant();
    }
    QHash<int, QByteArray> roleNames() const override {
        QHash<int, QByteArray> roles;
        roles[TableDataRole] = "tabledata";
        roles[HeadingRole] = "heading";
        return roles;
    }

    Q_INVOKABLE void addPerson() {
        beginInsertRows(QModelIndex(), rowCount(), rowCount());
        table.append({
                         "Marc",
                         "Fonz",
                         "25",
                     });
        endInsertRows();
    }
private:
    QVector<QVector<QString>> table;
};

MainWindow.h

#pragma once

#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "TableModel.h"

class MainWindow : public QObject {
    Q_OBJECT
public:
    explicit MainWindow() {
        engine_.rootContext()->setContextProperty("myModel", &model_);
        engine_.load(QUrl(QStringLiteral("qrc:/main.qml")));
    }
private:
    TableModel model_;
    QQmlApplicationEngine engine_;
};

main.qml

import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

import Qt.labs.settings 1.0
import Qt.labs.platform 1.0 as Platform

import QtQuick.Controls.Material 2.12

ApplicationWindow {
    id: window
    visible: true
    width: 1040
    height: 480
    ColumnLayout{
        spacing: 2
        anchors.fill: parent
        Button {
            text: qsTr("Update List Model")
            onClicked: myModel.addPerson()
        }
        TableView {
            width: 400
            height: 200
            columnSpacing: 1
            rowSpacing: 1
            clip: true
            ScrollIndicator.horizontal: ScrollIndicator { }
            ScrollIndicator.vertical: ScrollIndicator { }
            model: myModel
            delegate: Rectangle {
                implicitWidth: 100
                implicitHeight: 20
                border.color: "black"
                border.width: 2
                color: heading ? 'teal':"green"
                TableView.onPooled: console.log(tabledata + " pooled")
                TableView.onReused: console.log(tabledata + " resused")

                Text {
                    text: tabledata
                    font.pointSize: 10
                    anchors.centerIn: parent
                }
            }
        }
    }
}

Выход:

enter image description here


Полное решение можно найти здесь

...