说明
在 QML 表格类实现类时 QWidget 那样的自定义委托(也就是插入自定义控件)
输出函数位于 testsub.cpp/ setValue 中
源码
//file: main.cpp
#include <QGuiApplication>
#include <QQmlAppliction>
#include "testsub.h"
#include "testModel.h"
Q_DECLARE_METATYPE(TestSub*) //向 QML 声明指针
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
qmlRegisterType<TestModel>("MyDataModel", 1, 0, "TableModel");
qmlRegisterType<TestSub>(); //声明 TestSub 类型 Qt5.13 及以下版本使用
//qmlRegisterAnonymousType<TestSub>("MyDataModel", 1): //声明 TestSub 类型 Qt5.14 启用
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc::/main.qml"));
return app.exec();
}
Q_DECLARE_METATYPE 主要用于向 QML 注册已经声明类型的指针样式
qmlRegisterType 向 QML 注册(继承 QObject) 的类型(不支持摸板)
//file: main.qml
/*
这部分请按照自身 Qt 版本添加
import QtQuick 2.14
import QtQuick.Controls 1.4
import MyDataModel 1.0
*/
Window {
visible: true
width: 300
height: 480
TableView {
anchors.fill: parent
model: TableModel {
id: testModel
}
TableViewColumn {
role: "set" //取自 testmodel.cpp 中 roleNames() 函数定义
width: 100
delegate: TextInput {
property value workObj: null
anchors.fill: parent
Component.onCompleted : {
workObj = testModel.getItem(styleData.row, styData.column) //styleData 是 TableView 在 delegate 中自带变量,具体可以看官方文档
text = workObj.value
}
onTextEdited: {
workObj.value =text
}
}
}
}
}
由于是自定义控件,就直接使用 styleData 变量的属性值即可,当然这里使用了比较老的 TableViewColumn 也可以使用其它最新控件,使用方式类似
//file: testmodel.h
#include <QAbstractTableModel>
#include "testsub.h"
class TestModel : public QAbstractTableModel
{
Q_OBJECT
Q_ENUMS(TN) //向 QML 声明
public:
explicit TestModel(QObject *parent = nullptr);
~TestModel();
enum TN {
kSet = Qt::UserRole + 1, //由于 Qt 在宏已经定义了很多枚举类型,那么最好在 Qt::UserRole 之后再添加
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIdex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE TestSub* getItem(const int& row, const int& columns);
private:
QList <QHash<int, TestSub*>> mRecords;
};
rowCount columnCOunt data 都是对父类的重写
roleNames() 是 QML 下最为重要的函数,在 QML 中没有列的概念通过 role 代替
Q_INVOKABLE 就是声明这是一个槽 与在 public slots 下声明效果一样
//file: testmodel.cpp
#include "testmodel.h"
TestModel::TestModel(QObject *parent) : QAbstractTableModel(parent) {
int i = 0;
for (int j = 0; j < 10; ++j ) {
i++;
QHash<int, TestSub*> t;
t[0] = new TestSub(QString::number(i));
mRecords.append(t);
}
}
TestModel::~TestModel() {
}
int TestModel:: rowCount(const QModelIndex &parent) const {
return mRecords.count();
}
/// \brief 由于在 QML 没有列的概念但是必须要返回一个 >0 的数字,所以选择 1 具体看官方文档说明
int TestModel::columnCount(const QModelIndex &parent) const {
return 1;
}
/// \remark 这不我不需要使用其内部传值,所以直接返回空
QVariant TestModel:: data(const QModelIndex &index, int role) const {
return QVariant();
}
/// \remark 向QML 注册role 的名称和个数
QHash<int, QByteArray> TestModel::roleNames() const {
QHash<int, QByteArray> t;
t[kSet] = "set";
return t;
}
TestSub* TestModel::getItem(const int& row, const int& column) {
return mRecords.at(row)[kSet+column);
}
//file: testsub.h
#include <QObject>
class TestSub: public QObject
{
Q_OBJECT
Q_PROPERTY(QString value READ getValue WRITE setValue NOTIFY valueChanged)
public:
TestSub(const QString& _val, QObject *parent = nullptr);
~TestSub() ;
QString getValue();
void setValue(const QString& val);
private:
QString value;
};
//file: testsub.cpp
#include "testsub.h"
#include <QDebug>
TestSub::TestSub(const QString &_val, QObject *parent) : QObject (parent), value(_val) {
}
TestSub::~TestSub() {
}
QString TestSub::getValue() {
return value;
}
void TestSub::setValue() {
value = val;
qDebug() << "set value :" << value;
emit valueChanged();
}