使用自定义委托通过 TableView 编辑 QStandardItemModel [英] Edit QStandardItemModel via TableView with Custom Delegate
问题描述
我有一个 QStandardItemModel,我通过 QML 表视图显示.
这是模型:
class mystandardmodel: public QStandardItemModel{上市:我的标准模型();枚举角色{role1=Qt::UserRole,角色2};显式 mystandardmodel(QObject * parent = 0): QStandardItemModel(parent){}//明确的mystandardmodel(int rows, int columns, QObject * parent = 0 )//: QStandardItemModel(rows, columns, parent){}QHashroleNames() const{QHash角色;角色[role1] =一个";角色[role2] =两个";回归角色;}};
这是使用自定义委托显示模型的方式:
TableView {id:tableView2×:69y: 316宽度:318高度:150表视图列{标题:参数名称"角色:一个"}表视图列{书名:《价值》角色:二"委托:myDelegate}模型:myTestModel}成分 {id:我的委托装载机{属性 var roleTwo:model.twosourceComponent: if(typeof(roleTwo)=='boolean') {checkBoxDelegate}其他 { stringDelegate}}}成分 {id: checkBoxDelegate复选框{文本:roleTwo}}成分 {id:字符串委托文字编辑 {文字:roleTwo}}
我像这样填充模型:
mystandardmodel* mysmodel=new mystandardmodel(0);QStandardItem* it = new QStandardItem();it->setData("data1", mystandardmodel::role1);it->setData(true, mystandardmodel::role2);它-> setCheckable(true);它-> setEditable(true);mysmodel->appendRow(it);QStandardItem* it2 = new QStandardItem();it2->setData("data2",mystandardmodel::role1);it2->setData("teststring",mystandardmodel::role2);mysmodel->appendRow(it2);
如何使模型可编辑,以便使用复选框或编辑文本将返回到模型?
我尝试遵循 在 QML TableView 中点击编辑数据(如 excel) 并使用设置模型:
组件{id:我的委托装载机{属性 var roleTwo:model.two属性 int thisIndex: model.indexsourceComponent: if(typeof(roleTwo)=='boolean') {checkBoxDelegate}其他 { stringDelegate}}}成分 {id: checkBoxDelegate复选框{文本:roleTwoonCheckedChanged:{myTestModel.setData(0,"二",false)console.log('调用',thisIndex)}}}成分 {id:字符串委托文本编辑 {文本:roleTwoonEditingFinished:{myTestModel.setData(thisIndex,"two",text)console.log('调用',thisIndex)}}}
索引没问题,但好像没有效果(我添加了第二个相同模型的TableView,但是如果我在第一个TableView中编辑它,那里的数据没有更新)
Using setData()
可能是一个选项,但它需要一个整数值来指示在 QML 中无法访问的角色,或者说不优雅.
更好的选择是创建一个新的 Q_INVOKABLE
.因为更新是在视图中给出的,所以除了引起奇怪的事件之外,没有必要通知它.
我们使用几何体和TableView
的rowAt()
方法来获取行.
以下是一个例子:
main.cpp
#include #include #include #include 类 MyStandardModel:公共 QStandardItemModel{Q_OBJECT上市:枚举角色{role1=Qt::UserRole+1,角色2};使用 QStandardItemModel::QStandardItemModel;QHashroleNames() const{QHash角色;角色[role1] =一个";角色[role2] =两个";回归角色;}Q_INVOKABLE void updateValue(int row, QVariant value, const QString &roleName){int role = roleNames().key(roleName.toUtf8());QStandardItem *it = item(row);如果它){块信号(真);it->setData(value, role);Q_ASSERT(it->data(role)==value);块信号(假);}}};int main(int argc, char *argv[]){QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);MyStandardModel 模型;for(int i=0; i<10; i++){自动项目 = 新 QStandardItem;item->setData(QString("data1 %1").arg(i), MyStandardModel::role1);如果(我%2 == 0)item->setData(true, MyStandardModel::role2);别的 {item->setData(QString("data2 %1").arg(i), MyStandardModel::role2);}model.appendRow(item);}QQmlApplicationEngine 引擎;engine.rootContext()->setContextProperty("myTestModel", &model);engine.load(QUrl(QStringLiteral("qrc:/main.qml")));如果 (engine.rootObjects().isEmpty())返回-1;返回 app.exec();}#include "main.moc"
main.qml
导入QtQuick 2.9导入 QtQuick.Window 2.2导入 QtQuick.Controls 1.4窗户 {可见:真实宽度:640高度:480标题:qsTr("Hello World")表视图{id:tableView2anchors.fill:父级表视图列{标题:参数名称"角色:一个"}表视图列{书名:《价值》角色:二"委托:myDelegate}模型:myTestModel}成分 {id:我的委托装载机{属性 var roleTwo:model.twosourceComponent: typeof(roleTwo)=='boolean'?checkBoxDelegate: stringDelegate}}成分 {id: checkBoxDelegate复选框{选中:roleTwoonCheckedChanged:{var pos = mapToGlobal(0, 0)var p = tableView2.mapFromGlobal(pos.x, pos.y)var row = tableView2.rowAt(p.x, p.y)如果(行> = 0)myTestModel.updateValue(tableView2.row, 选中, "两个")}}}成分 {id:字符串委托文本域 {文字:角色二onEditingFinished:{var pos = mapToGlobal(0, 0)var p = tableView2.mapFromGlobal(pos.x, pos.y)var row = tableView2.rowAt(p.x, p.y)如果(行> = 0)myTestModel.updateValue(tableView2.row, text, "two")}}}}
完整示例可在以下链接中找到.>
I have a QStandardItemModel which I display via a QML Table view.
Here is the model:
class mystandardmodel: public QStandardItemModel
{
public:
mystandardmodel();
enum Role {
role1=Qt::UserRole,
role2
};
explicit mystandardmodel(QObject * parent = 0): QStandardItemModel(parent){}
//explicit mystandardmodel( int rows, int columns, QObject * parent = 0 )
// : QStandardItemModel(rows, columns, parent){}
QHash<int, QByteArray> roleNames() const{
QHash<int, QByteArray> roles;
roles[role1] = "one";
roles[role2] = "two";
return roles;
}
};
and this is how the model is displayed using custom delegates:
TableView {
id: tableView2
x: 69
y: 316
width: 318
height: 150
TableViewColumn {
title: "Parameter Name"
role: "one"
}
TableViewColumn {
title: "Value"
role: "two"
delegate: myDelegate
}
model: myTestModel
}
Component {
id: myDelegate
Loader {
property var roleTwo: model.two
sourceComponent: if(typeof(roleTwo)=='boolean') {
checkBoxDelegate}
else { stringDelegate}
}
}
Component {
id: checkBoxDelegate
CheckBox{text: roleTwo}
}
Component {
id: stringDelegate
TextEdit {text: roleTwo}
}
I populated the model like this:
mystandardmodel* mysmodel=new mystandardmodel(0);
QStandardItem* it = new QStandardItem();
it->setData("data1", mystandardmodel::role1);
it->setData(true, mystandardmodel::role2);
it->setCheckable(true);
it->setEditable(true);
mysmodel->appendRow(it);
QStandardItem* it2 = new QStandardItem();
it2->setData("data2",mystandardmodel::role1);
it2->setData("teststring",mystandardmodel::role2);
mysmodel->appendRow(it2);
How can I make the model editable, so that using the checkBox or editing the text is transfered back to the model?
Edit: I tried to follow the suggestion in In QML TableView when clicked edit a data (like excel) and use set model:
Component {
id: myDelegate
Loader {
property var roleTwo: model.two
property int thisIndex: model.index
sourceComponent: if(typeof(roleTwo)=='boolean') {
checkBoxDelegate}
else { stringDelegate}
}
}
Component {
id: checkBoxDelegate
CheckBox{text: roleTwo
onCheckedChanged: {
myTestModel.setData(0,"two",false)
console.log('called',thisIndex)
}
}
}
Component {
id: stringDelegate
TextEdit {text: roleTwo
onEditingFinished: {
myTestModel.setData(thisIndex,"two",text)
console.log('called',thisIndex)
}
}
}
The index is OK, but it seems that it does not have an effect (I added a second TableView with the same model, but the data there does not get updated if I edit it in the first TableView)
Using setData()
could be an option, but it requires an integer value that indicates the role that is not accessible in QML, or rather is not elegant.
A better option is to create a new one that is Q_INVOKABLE
. As the update is given in the view it is not necessary to notify it besides causing strange events.
to obtain the row we use the geometry and the rowAt()
method of TableView
.
The following is an example:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QStandardItemModel>
class MyStandardModel: public QStandardItemModel
{
Q_OBJECT
public:
enum Role {
role1=Qt::UserRole+1,
role2
};
using QStandardItemModel::QStandardItemModel;
QHash<int, QByteArray> roleNames() const{
QHash<int, QByteArray> roles;
roles[role1] = "one";
roles[role2] = "two";
return roles;
}
Q_INVOKABLE void updateValue(int row, QVariant value, const QString &roleName){
int role = roleNames().key(roleName.toUtf8());
QStandardItem *it = item(row);
if(it){
blockSignals(true);
it->setData(value, role);
Q_ASSERT(it->data(role)==value);
blockSignals(false);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
MyStandardModel model;
for(int i=0; i< 10; i++){
auto item = new QStandardItem;
item->setData(QString("data1 %1").arg(i), MyStandardModel::role1);
if(i%2 == 0)
item->setData(true, MyStandardModel::role2);
else {
item->setData(QString("data2 %1").arg(i), MyStandardModel::role2);
}
model.appendRow(item);
}
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("myTestModel", &model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
TableView {
id: tableView2
anchors.fill: parent
TableViewColumn {
title: "Parameter Name"
role: "one"
}
TableViewColumn {
title: "Value"
role: "two"
delegate: myDelegate
}
model: myTestModel
}
Component {
id: myDelegate
Loader {
property var roleTwo: model.two
sourceComponent: typeof(roleTwo)=='boolean'? checkBoxDelegate: stringDelegate
}
}
Component {
id: checkBoxDelegate
CheckBox{
checked: roleTwo
onCheckedChanged:{
var pos = mapToGlobal(0, 0)
var p = tableView2.mapFromGlobal(pos.x, pos.y)
var row = tableView2.rowAt(p.x, p.y)
if(row >= 0)
myTestModel.updateValue(tableView2.row, checked, "two")
}
}
}
Component {
id: stringDelegate
TextField {
text: roleTwo
onEditingFinished: {
var pos = mapToGlobal(0, 0)
var p = tableView2.mapFromGlobal(pos.x, pos.y)
var row = tableView2.rowAt(p.x, p.y)
if(row >= 0)
myTestModel.updateValue(tableView2.row, text, "two")
}
}
}
}
The complete example can be found in the following link.
这篇关于使用自定义委托通过 TableView 编辑 QStandardItemModel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!