Многоразовый EditorDelegate для QML TreeView - PullRequest
0 голосов
/ 09 января 2019

Я пытаюсь выяснить, как создать повторно используемую EditorDelegate для компонента QML TreeView.

Мне удалось создать работоспособного делегата-редактора для одного столбца с ролью end. Но у моего TreeView есть 3 столбца, а именно name, start и end.

Я попытался просто установить 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 не имеет средств для открытия и свертывания узлов дерева. Но это совсем другая история.

1 Ответ

0 голосов
/ 09 января 2019

Идея состоит в том, что компонент четко устанавливает входы и выходы, и в вашем случае компонент очень связан с представлением, поэтому он будет мало пригоден для повторного использования. Лучшим дизайном является предоставление только свойства, которое обновляется данными модели, а также уведомляет об этом, когда оно изменилось.

В делегате я предпочитаю использовать Loader для отображения редактора при необходимости.

main.cpp

#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
            }
        }
    }
}
...