通过 C++ 单击按钮后更新 QML TableView
Posted
技术标签:
【中文标题】通过 C++ 单击按钮后更新 QML TableView【英文标题】:Update QML TableView after Button click via C++ 【发布时间】:2019-04-21 22:01:33 【问题描述】:我想通过按一个按钮向 QML 表视图添加一定数量的行。用户界面如下所示:
按下“更新列表模型”后,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
【问题讨论】:
显示您的 TableModel。 @eyllanesc 复制了 MainWindow.h 而不是 TableModel.h - 现在已修复 【参考方案1】:您有以下错误:
在 addPerson 中,您要添加一行,因此不应使用 dataChanged,因为该信号表明已存在的内容已被修改,而应使用 beginInsertRows() 和 endInsertRows()。
在 MainWindow 中创建的 TableModel 与在 QML 中创建的 TableModel 不同。
您无需在 main.cpp 中创建 QQmlApplicationEngine,因为您只需在 MainWindow 中使用。
您必须将业务逻辑与视图分开,因此将对象从 QML 导出到 C++ 被认为是不好的做法。
综合以上情况,解决办法是:
将 addPerson 方法设为 Q_INVOKABLE,以便在 QML 中可访问。
使用 setContextProperty 将启动时的 TableModel 导出到 QML,因此无需注册 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
输出:
完整的解决方案可以在here
【讨论】:
以上是关于通过 C++ 单击按钮后更新 QML TableView的主要内容,如果未能解决你的问题,请参考以下文章