我想通过按一个按钮将一定数量的行添加到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
}
}
}
}
}
答案 0 :(得分:2)
您遇到以下错误:
在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