使用自定义委托通过 TableView 编辑 QStandardItemModel [英] Edit QStandardItemModel via TableView with Custom Delegate

查看:82
本文介绍了使用自定义委托通过 TableView 编辑 QStandardItemModel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 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.因为更新是在视图中给出的,所以除了引起奇怪的事件之外,没有必要通知它.

我们使用几何体和TableViewrowAt()方法来获取行.

以下是一个例子:

ma​​in.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"

ma​​in.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆