首页 > 解决方案 > QML TreeView 的可重用 EditorDelegate

问题描述

我试图弄清楚如何EditorDelegate为 QMLTreeView组件创建可重用的。

我能够为一个具有角色的列创建一个可行的编辑器委托end。但 my有 3 列,TreeView即和。namestartend

我试图简单地设置styleData.value=textEdit.text而不是modelEnd=textEdit.text,但似乎styleData.value是一个只读属性。

如何使我EditorDelegate的所有列都可重复使用?

EditorDelegate.qml 导入 QtQuick 2.0

Rectangle {
    anchors.fill: parent

    Text {
        anchors.fill: parent
        id: textDisplay
        visible: true
        text: styleData.value
    }

    TextInput {
        anchors.fill: parent
        id: textEdit
        text: styleData.value
        visible: false
        onVisibleChanged: {
            focus: parent
        }

        onAccepted: {
            model.end=textEdit.text; // Can be model.name, model.start, model.<role>???
            textEdit.visible=false
            textDisplay.visible=true
        }
        onFocusChanged: {
            if (!focus) {
                textEdit.visible=false
                styleData.value=textEdit.text
                textDisplay.visible=true
            }

        }
    }

    MouseArea {
        id: mouseArea
        acceptedButtons: Qt.AllButtons

        anchors.fill: parent

        onDoubleClicked: {
            if (mouse.button & Qt.LeftButton) {
                textDisplay.visible=false
                textEdit.visible=true
                textEdit.forceActiveFocus()
            }
        }
    }
}

用法应该是这样的:

import QtQuick 2.9
import QtQuick.Window 2.3
import QtQuick.Controls 1.4

Window {
    visible: true

    TreeView {
        id: treeView
        anchors.fill: parent

        TableViewColumn {
            title: "Value"
            role: "name"
            delegate: EditorDelegate { }
        }        

        TableViewColumn {
            title: "Start"
            id: start
            role: "start"
            delegate: EditorDelegate {   }
        }

        TableViewColumn {
            title: "End"
            id: end
            role: "end"
            delegate: EditorDelegate {  }
        }

        model: itemModel
    }
}

这里我有另一个问题,因为EditorDelegate无法打开和折叠树节点。但这是一个完全不同的故事。

标签: qttreeviewqmlqabstractitemmodel

解决方案


这个想法是组件清楚地建立了入口和出口,并且在您的情况下,组件与视图非常相关,因此它几乎不能重用。更好的设计是只公开一个随模型数据更新的属性,并在它发生变化时通知它。

在委托中,我更喜欢在必要时使用加载器来显示编辑器。

主文件

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QStandardItemModel>

#include <QDebug>

enum CustomRoles {
    NameRole = Qt::UserRole + 1000,
    StartRole,
    EndRole
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QStandardItemModel model;
    QObject::connect(&model, &QStandardItemModel::itemChanged, [](QStandardItem *item){
        qDebug()<< item->data(StartRole);
    });
    QHash<int, QByteArray> roles;
    roles[NameRole] = "name";
    roles[StartRole] = "start";
    roles[EndRole] = "end";
    model.setItemRoleNames(roles);

    for(int i=0; i<4; ++i){
        QStandardItem *parent_item = new QStandardItem();
        model.invisibleRootItem()->appendRow(parent_item);
        parent_item->setData(QString("name-%1").arg(i), NameRole);
        parent_item->setData(QString("start-%1").arg(i), StartRole);
        parent_item->setData(QString("end-%1").arg(i), EndRole);
        for (int j=0; j<5; ++j) {
            QStandardItem *child_item = new QStandardItem();
            parent_item->appendRow(child_item);
            child_item->setData(QString("name-%1-%2").arg(i).arg(j), NameRole);
            child_item->setData(QString("start-%1-%2").arg(i).arg(j), StartRole);
            child_item->setData(QString("end-%1-%2").arg(i).arg(j), EndRole);
        }
    }
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("itemModel", &model);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

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")
    TreeView {
        id: treeView
        anchors.fill: parent
        TableViewColumn {
            title: "Value"
            role: "name"
            delegate: EditorDelegate{
                text: styleData.value
                onTextChanged: model.name = text
            }
        }
        TableViewColumn {
            title: "Start"
            id: start
            role: "start"
            delegate: EditorDelegate{
                text: styleData.value
                onTextChanged: model.start = text
            }
        }
        TableViewColumn {
            title: "End"
            id: end
            role: "end"
            delegate: EditorDelegate{
                text: styleData.value
                onTextChanged: model.end = text
            }
        }
        model: itemModel
    }
}

EditorDelegate.qml

import QtQuick 2.0

Rectangle {
    id: root
    property string text
    property bool mode: false
    Component{
        id: component_display
        Text{}
    }
    Component{
        id: component_edit
        TextInput{}
    }
    Loader{
        id: loader
        anchors.fill: parent
        sourceComponent: mode ? component_edit: component_display
        onSourceComponentChanged: {
            loader.item.text = root.text
            if(sourceComponent === component_edit){
                loader.item.editingFinished.connect(onEditingFinished)
                loader.item.forceActiveFocus()
            }
        }
        function onEditingFinished(){
            text = loader.item.text
            mode = false
        }
        MouseArea{
            anchors.fill: parent
            onDoubleClicked: {
                if (mouse.button & Qt.LeftButton)
                    mode = true
            }
        }
    }
}

推荐阅读