如何从 C++ 更改 qml 中 TableView 的模型 属性
How does one change the model property of a TableView in qml from c++
我是 QT 的新手,所以非常感谢任何帮助!
我正在开发 Qt Quick 应用程序,为 UI 使用 QQmlApplicationEngine。我制作了 QAbstractTableModel 的子类并实现了必要的功能并成功地创建并在 Window 上显示了一个(单数)table。
目前,我在 QML 文件中 link 编辑模型的方式是设置 root context 属性 属性 QQmlApplicationEngine。
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSharedPointer>
#include <QQmlContext>
#include "tablecontroller.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QSharedPointer<QQmlApplicationEngine> engine =
QSharedPointer<QQmlApplicationEngine>::create();
TableController theController(engine.toWeakRef());
engine.data()->rootContext()->setContextProperty("TableController", &theController);
engine.data()->load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
tabcontroller.h
#ifndef TABLECONTROLLER_H
#define TABLECONTROLLER_H
#include <QObject>
#include <QQmlApplicationEngine>
#include <QWeakPointer>
#include <QHash>
#include <QList>
#include "tablemodel.h"
class TableController : public QObject
{
Q_OBJECT
public:
explicit TableController(QWeakPointer<QQmlApplicationEngine> Engine, QObject *parent = 0);
Q_INVOKABLE void AddEntry();
signals:
public slots:
private:
TE::TDT::TableModel m_TableModel;
QList<QString> m_Headings;
};
#endif // TABLECONTROLLER_H
tabcontroller.cpp
#include "tablecontroller.h"
#include <QQmlContext>
TableController::TableController(QWeakPointer<QQmlApplicationEngine> Engine, QObject *parent) : QObject(parent)
{
m_Headings << "Heading1" << "Heading2" << "Heading3" << "Heading4";
m_TableModel.setColumnHeadings(m_Headings);
Engine.data()->rootContext()->setContextProperty("myModel", &m_TableModel);
}
void TableController::AddEntry()
{
QHash<QString, QVariant> tempHash;
int counter = 1;
for (auto x : m_Headings)
{
tempHash.insert(x, QString::number(counter));
counter++;
}
m_TableModel.addElement(tempHash);
}
tablemodel.h
#ifndef TABLEMODEL_H
#define TABLEMODEL_H
#include <QObject>
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include <QList>
#include <QString>
#include <QHash>
namespace TE {
namespace TDT {
class TableModel : public QAbstractTableModel
{
Q_OBJECT
Q_PROPERTY(QStringList userRoleNames READ userRoleNames CONSTANT)
public:
explicit TableModel(QObject *parent = 0);
enum MyModelRoles {
UserRole1 = Qt::UserRole + 1,
UserRole2,
};
void setFirstColumn(const QList<QString> &FirstColumn);
void setColumnHeadings(const QList<QString> &ColumnHeadings);
void addElement(const QHash<QString, QVariant> Entry);
QStringList userRoleNames();
signals:
public slots:
// QAbstractTableModel interface
public:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QHash<int, QByteArray> roleNames() const override;
private:
QList<QHash<QString, QVariant>> m_TableData;
QList<QString> m_ColumnHeadings;
QMap<int, QString> m_roleNames;
};
}// TDT
}// TE
#endif // TABLEMODEL_H
tablemodel.cpp
#include "tablemodel.h"
#include <QDebug>
#include <QAbstractListModel>
TE::TDT::TableModel::TableModel(QObject *parent) : QAbstractTableModel(parent)
{
}
int TE::TDT::TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_TableData.count();
}
int TE::TDT::TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_ColumnHeadings.count();
}
QVariant TE::TDT::TableModel::data(const QModelIndex &index, int role) const
{
QVariant retVal;
try {
if(!index.isValid())
{
throw QString("Invalid index for inherited data function");
}
// Check row index
if(index.row() >= m_TableData.count() || index.row() < 0)
{
throw QString("Index (row) out of bounds for data function");
}
//Check column index
if(index.column() >= m_ColumnHeadings.count() || index.column() < 0)
{
throw QString("Index (column) out of bounds for data function");
}
QList<int> keys = m_roleNames.keys();
if(role == Qt::DisplayRole || role == Qt::EditRole)
{
QString colKey = m_ColumnHeadings.at(index.column());
if (m_TableData.at(index.row()).value(colKey).isNull())
{
retVal = QVariant();
} else {
retVal = m_TableData.at(index.row()).value(colKey);
}
} else if (m_roleNames.keys().contains(role)) {
QHash<QString, QVariant> temp1 = m_TableData.at(index.row());
retVal = m_TableData.at(index.row()).value(m_roleNames.value(role));
}
return retVal;
} catch (QString &e) {
qDebug() << e;
return QVariant();
}
}
QVariant TE::TDT::TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
Q_UNUSED(orientation);
QVariant retVal;
if (role == Qt::DisplayRole)
{
retVal = m_ColumnHeadings.at(section);
}
return retVal;
}
QHash<int, QByteArray> TE::TDT::TableModel::roleNames() const {
// Populate the roles - basically the column headings
QHash<int, QByteArray> roles = QAbstractTableModel::roleNames();
// Should not overwrite existing roles
int LastIndexOfUserRole = Qt::UserRole;
for (int x = 1; x <= m_ColumnHeadings.count(); x++)
{
roles[LastIndexOfUserRole + x] = m_ColumnHeadings.at(x-1).toUtf8();
}
return roles;
}
QStringList TE::TDT::TableModel::userRoleNames() // Return ordered List of user-defined roles
{
QHashIterator<int, QByteArray> i(roleNames());
while (i.hasNext())
{
i.next();
if(i.key() > Qt::UserRole)
{
m_roleNames[i.key()] = i.value();
}
}
return m_roleNames.values();
}
void TE::TDT::TableModel::setColumnHeadings(const QList<QString> &ColumnHeadings)
{
m_ColumnHeadings = ColumnHeadings;
}
void TE::TDT::TableModel::addElement(const QHash<QString, QVariant> Entry)
{
beginInsertRows(QModelIndex(), this->rowCount(QModelIndex()), this->rowCount(QModelIndex()));
m_TableData.append(Entry);
endInsertRows();
}
main.qml
导入 QtQuick 2.5
导入 QtQuick.Window 2.2
导入 QtQuick.Controls 1.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: mainwindow
// template component for the column headings
Component
{
id: columnComponent
TableViewColumn{width: 100 }
}
TableView {
id: tableview
height: mainwindow.height - 50
width: mainwindow.width
y: 5
x: 0
visible: true
resources:
{
var roleList = myModel.userRoleNames
var temp = []
for(var i = 0; i < roleList.length; i++)
{
var role = roleList[i]
temp.push(columnComponent.createObject(tableview, { "role": role, "title": role}))
}
return temp
}
model: myModel
}
Rectangle {
id: abutton
anchors.top: tableview.bottom
height: 40
width: mainwindow.width
Text {
text: "Click to Add"
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
TableController.AddEntry()
}
}
}
}
代码改编自:
QML TableView with dynamic number of columns
现在,我的问题是,如果我想重新使用 main.qml 中定义的 TableView我想为它使用另一个 model。问题是(根据我有限的理解)QML link 中的模型 "variable" 是静态的(在启动时定义),在本例中为 "myModel"。
创建此 TableView 的另一个 实例 后如何更改模型?我每次都必须 link 另一个 "variable" 吗?
我试图将 TableView(在 QML 中)转换为 QQuickItem(在 C++ 中)并尝试在那里设置 属性,但无济于事(给出空值,但 QQuickItem 也没有"setModel" 函数)
很抱歉post,想提供尽可能多的信息。
正如@folibis 所说,一种选择是使您的模型可从 QML 实例化,即您可以在 QML 中创建模型的实例。
然后您可以将方法添加到 TableController
到 "register" 这些实例,以防控制器需要知道它们。
或者您仍然在 TableController
中创建模型并使它们可访问,例如通过每个模型一个 属性,一个列表 属性 或 Q_INVOKABLE
方法。
如果我对你的问题的理解正确,你需要将你的自定义 TableView
重新用于另一个模型,你真的不需要更改现有 TableView
的 model
。
为此,您可以在单独的文件中定义一个新组件并在其他地方使用它(这里有一些文档:http://doc.qt.io/qt-5/qtqml-documents-definetypes.html)
在你的情况下它可能看起来像这样:
DynamicTableView.qml
:
TableView {
//it's better not to set positioning properties in a component definition file.
Component {
id: columnComponent
TableViewColumn { width: 100 }
}
resources:
{
var roleList = model.userRoleNames // here you expect all your models to be an instance of your TableModel
var temp = []
for(var i = 0; i < roleList.length; i++)
{
var role = roleList[i]
temp.push(columnComponent.createObject(tableview, { "role": role, "title": role}))
}
return temp
}
}
然后您可以在 main.qml
中重用您的组件并定义其 model
属性 :
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: mainwindow
DynamicTableView {
id: tableview
height: mainwindow.height - 50
width: mainwindow.width
y: 5
x: 0
model: myModel
}
Rectangle {
id: abutton
anchors.top: tableview.bottom
height: 40
width: mainwindow.width
Text {
text: "Click to Add"
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
TableController.AddEntry()
}
}
}
}
这个人救了我的命 :D
所以看来我需要使用 component.beginCreate() 函数。
我是 QT 的新手,所以非常感谢任何帮助!
我正在开发 Qt Quick 应用程序,为 UI 使用 QQmlApplicationEngine。我制作了 QAbstractTableModel 的子类并实现了必要的功能并成功地创建并在 Window 上显示了一个(单数)table。
目前,我在 QML 文件中 link 编辑模型的方式是设置 root context 属性 属性 QQmlApplicationEngine。
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSharedPointer>
#include <QQmlContext>
#include "tablecontroller.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QSharedPointer<QQmlApplicationEngine> engine =
QSharedPointer<QQmlApplicationEngine>::create();
TableController theController(engine.toWeakRef());
engine.data()->rootContext()->setContextProperty("TableController", &theController);
engine.data()->load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
tabcontroller.h
#ifndef TABLECONTROLLER_H
#define TABLECONTROLLER_H
#include <QObject>
#include <QQmlApplicationEngine>
#include <QWeakPointer>
#include <QHash>
#include <QList>
#include "tablemodel.h"
class TableController : public QObject
{
Q_OBJECT
public:
explicit TableController(QWeakPointer<QQmlApplicationEngine> Engine, QObject *parent = 0);
Q_INVOKABLE void AddEntry();
signals:
public slots:
private:
TE::TDT::TableModel m_TableModel;
QList<QString> m_Headings;
};
#endif // TABLECONTROLLER_H
tabcontroller.cpp
#include "tablecontroller.h"
#include <QQmlContext>
TableController::TableController(QWeakPointer<QQmlApplicationEngine> Engine, QObject *parent) : QObject(parent)
{
m_Headings << "Heading1" << "Heading2" << "Heading3" << "Heading4";
m_TableModel.setColumnHeadings(m_Headings);
Engine.data()->rootContext()->setContextProperty("myModel", &m_TableModel);
}
void TableController::AddEntry()
{
QHash<QString, QVariant> tempHash;
int counter = 1;
for (auto x : m_Headings)
{
tempHash.insert(x, QString::number(counter));
counter++;
}
m_TableModel.addElement(tempHash);
}
tablemodel.h
#ifndef TABLEMODEL_H
#define TABLEMODEL_H
#include <QObject>
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include <QList>
#include <QString>
#include <QHash>
namespace TE {
namespace TDT {
class TableModel : public QAbstractTableModel
{
Q_OBJECT
Q_PROPERTY(QStringList userRoleNames READ userRoleNames CONSTANT)
public:
explicit TableModel(QObject *parent = 0);
enum MyModelRoles {
UserRole1 = Qt::UserRole + 1,
UserRole2,
};
void setFirstColumn(const QList<QString> &FirstColumn);
void setColumnHeadings(const QList<QString> &ColumnHeadings);
void addElement(const QHash<QString, QVariant> Entry);
QStringList userRoleNames();
signals:
public slots:
// QAbstractTableModel interface
public:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QHash<int, QByteArray> roleNames() const override;
private:
QList<QHash<QString, QVariant>> m_TableData;
QList<QString> m_ColumnHeadings;
QMap<int, QString> m_roleNames;
};
}// TDT
}// TE
#endif // TABLEMODEL_H
tablemodel.cpp
#include "tablemodel.h"
#include <QDebug>
#include <QAbstractListModel>
TE::TDT::TableModel::TableModel(QObject *parent) : QAbstractTableModel(parent)
{
}
int TE::TDT::TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_TableData.count();
}
int TE::TDT::TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_ColumnHeadings.count();
}
QVariant TE::TDT::TableModel::data(const QModelIndex &index, int role) const
{
QVariant retVal;
try {
if(!index.isValid())
{
throw QString("Invalid index for inherited data function");
}
// Check row index
if(index.row() >= m_TableData.count() || index.row() < 0)
{
throw QString("Index (row) out of bounds for data function");
}
//Check column index
if(index.column() >= m_ColumnHeadings.count() || index.column() < 0)
{
throw QString("Index (column) out of bounds for data function");
}
QList<int> keys = m_roleNames.keys();
if(role == Qt::DisplayRole || role == Qt::EditRole)
{
QString colKey = m_ColumnHeadings.at(index.column());
if (m_TableData.at(index.row()).value(colKey).isNull())
{
retVal = QVariant();
} else {
retVal = m_TableData.at(index.row()).value(colKey);
}
} else if (m_roleNames.keys().contains(role)) {
QHash<QString, QVariant> temp1 = m_TableData.at(index.row());
retVal = m_TableData.at(index.row()).value(m_roleNames.value(role));
}
return retVal;
} catch (QString &e) {
qDebug() << e;
return QVariant();
}
}
QVariant TE::TDT::TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
Q_UNUSED(orientation);
QVariant retVal;
if (role == Qt::DisplayRole)
{
retVal = m_ColumnHeadings.at(section);
}
return retVal;
}
QHash<int, QByteArray> TE::TDT::TableModel::roleNames() const {
// Populate the roles - basically the column headings
QHash<int, QByteArray> roles = QAbstractTableModel::roleNames();
// Should not overwrite existing roles
int LastIndexOfUserRole = Qt::UserRole;
for (int x = 1; x <= m_ColumnHeadings.count(); x++)
{
roles[LastIndexOfUserRole + x] = m_ColumnHeadings.at(x-1).toUtf8();
}
return roles;
}
QStringList TE::TDT::TableModel::userRoleNames() // Return ordered List of user-defined roles
{
QHashIterator<int, QByteArray> i(roleNames());
while (i.hasNext())
{
i.next();
if(i.key() > Qt::UserRole)
{
m_roleNames[i.key()] = i.value();
}
}
return m_roleNames.values();
}
void TE::TDT::TableModel::setColumnHeadings(const QList<QString> &ColumnHeadings)
{
m_ColumnHeadings = ColumnHeadings;
}
void TE::TDT::TableModel::addElement(const QHash<QString, QVariant> Entry)
{
beginInsertRows(QModelIndex(), this->rowCount(QModelIndex()), this->rowCount(QModelIndex()));
m_TableData.append(Entry);
endInsertRows();
}
main.qml 导入 QtQuick 2.5 导入 QtQuick.Window 2.2 导入 QtQuick.Controls 1.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: mainwindow
// template component for the column headings
Component
{
id: columnComponent
TableViewColumn{width: 100 }
}
TableView {
id: tableview
height: mainwindow.height - 50
width: mainwindow.width
y: 5
x: 0
visible: true
resources:
{
var roleList = myModel.userRoleNames
var temp = []
for(var i = 0; i < roleList.length; i++)
{
var role = roleList[i]
temp.push(columnComponent.createObject(tableview, { "role": role, "title": role}))
}
return temp
}
model: myModel
}
Rectangle {
id: abutton
anchors.top: tableview.bottom
height: 40
width: mainwindow.width
Text {
text: "Click to Add"
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
TableController.AddEntry()
}
}
}
}
代码改编自: QML TableView with dynamic number of columns
现在,我的问题是,如果我想重新使用 main.qml 中定义的 TableView我想为它使用另一个 model。问题是(根据我有限的理解)QML link 中的模型 "variable" 是静态的(在启动时定义),在本例中为 "myModel"。
创建此 TableView 的另一个 实例 后如何更改模型?我每次都必须 link 另一个 "variable" 吗?
我试图将 TableView(在 QML 中)转换为 QQuickItem(在 C++ 中)并尝试在那里设置 属性,但无济于事(给出空值,但 QQuickItem 也没有"setModel" 函数)
很抱歉post,想提供尽可能多的信息。
正如@folibis 所说,一种选择是使您的模型可从 QML 实例化,即您可以在 QML 中创建模型的实例。
然后您可以将方法添加到 TableController
到 "register" 这些实例,以防控制器需要知道它们。
或者您仍然在 TableController
中创建模型并使它们可访问,例如通过每个模型一个 属性,一个列表 属性 或 Q_INVOKABLE
方法。
如果我对你的问题的理解正确,你需要将你的自定义 TableView
重新用于另一个模型,你真的不需要更改现有 TableView
的 model
。
为此,您可以在单独的文件中定义一个新组件并在其他地方使用它(这里有一些文档:http://doc.qt.io/qt-5/qtqml-documents-definetypes.html)
在你的情况下它可能看起来像这样:
DynamicTableView.qml
:
TableView {
//it's better not to set positioning properties in a component definition file.
Component {
id: columnComponent
TableViewColumn { width: 100 }
}
resources:
{
var roleList = model.userRoleNames // here you expect all your models to be an instance of your TableModel
var temp = []
for(var i = 0; i < roleList.length; i++)
{
var role = roleList[i]
temp.push(columnComponent.createObject(tableview, { "role": role, "title": role}))
}
return temp
}
}
然后您可以在 main.qml
中重用您的组件并定义其 model
属性 :
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: mainwindow
DynamicTableView {
id: tableview
height: mainwindow.height - 50
width: mainwindow.width
y: 5
x: 0
model: myModel
}
Rectangle {
id: abutton
anchors.top: tableview.bottom
height: 40
width: mainwindow.width
Text {
text: "Click to Add"
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
TableController.AddEntry()
}
}
}
}
这个人救了我的命 :D 所以看来我需要使用 component.beginCreate() 函数。