PySide2/QML将操作附加到工具栏并导航层次结构

2024-10-02 22:23:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图用QML实现下面帖子中提到的目标。
Breadcrumbs navigation using QToolBar and QListView

我不知道如何通过PySide2将ToolButton附加到QML工具栏并相对更新Gridview(基于给定的层次数据)。你知道吗

主.qml

import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQuick.Controls.Styles 1.4

ApplicationWindow {
    id: mainWindowId
    visible: true
    width: 960
    height: 540
    title: qsTr("Breadcrumbs Test")

    Rectangle {
        width: parent.width
        height: parent.height

        ColumnLayout {
            width: parent.width
            height: parent.height
            spacing: 6

            TextField {
                id: filterTextFieldId
                Layout.fillWidth: true
                Layout.preferredHeight: 40
                font {
                    family: "SF Pro Display"
                 pixelSize: 22
                }
                placeholderText: "Type Filter Expression"
                color: "dodgerblue"
            }

            ToolBar {

                background: Rectangle {
                    color: "transparent"
                }

                RowLayout {
                    anchors.fill: parent
                    spacing: 10

                    ToolButton {
                        Layout.preferredHeight: 20
                        contentItem: Text {
                                text: qsTr('Home')
                                color: "#FFFFFF"
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                            }
                        background: Rectangle {
                                    radius: 12
                                    color:  "#40e0d0"
                                }
                        onClicked: crumbsNavigation.on_buttonTriggered()
                    }

                    ToolButton {
                        Layout.preferredHeight: 20
                        contentItem: Text {
                                text: qsTr('About')
                                color: "#FFFFFF"
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                            }
                        background: Rectangle {
                                    radius: 12
                                    color:  "#40e0d0"
                                }
                        onClicked: crumbsNavigation.on_buttonTriggered()
                    }

                    ToolButton {
                        Layout.preferredHeight: 20
                        contentItem: Text {
                                text: qsTr('Contact')
                                color: "#FFFFFF"
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                            }
                        background: Rectangle {
                                    radius: 12
                                    color:  "#40e0d0"
                                }
                        onClicked: crumbsNavigation.on_buttonTriggered()
                    }
                }
            }

            Rectangle {
                Layout.fillWidth: true
                Layout.fillHeight: true
                color: "dodgerblue"

                GridView {
                    id: crumbsViewId
                    width: parent.width
                    height: parent.height
                    anchors.fill: parent
                    anchors.margins: 12
                    cellWidth: 130
                    cellHeight: 130
                    model: crumbsNavigation.model
                    delegate: Text {text:qsTr('Hello'); color:"white"}
                    focus: true

                }
            }
        }
    }
}

qmlbreads.py文件

from PySide2 import QtCore, QtQuick, QtGui, QtWidgets, QtQml
import os
import sys
import re

crumbs_data = {"books":{
    "web":{
      "front-end":{
        "html":["the missing manual", "core html5 canvas"],
        "css":["css pocket reference", "css in depth"],
        "js":["you don't know js", "eloquent javascript"]
      },
      "back-end":{
        "php":["modern php", "php web services"],
        "python":["dive into python", "python for everybody", 
        "Think Python", "Effective Python", "Fluent Python"]
      }
    },
    "database":{
      "sql":{
        "mysql":["mysql in a nutshell", "mysql cookbook"],
        "postgresql":["postgresql up and running", "practical postgresql"]
      },
      "nosql":{
        "mongodb":["mongodb in action", "scaling mongodb"],
        "cassandra":["practical cassandra", "mastering cassandra"]
}}}}


def dict_to_model(item, d):
    if isinstance(d, dict):
        for k, v in d.items():
            it = QtGui.QStandardItem(k)
            item.appendRow(it)
            dict_to_model(it, v)
    elif isinstance(d, list):
        for v in d:
            dict_to_model(item, v)
    else:
        item.appendRow(QtGui.QStandardItem(str(d)))

class crumbsNavigation(QtCore.QObject):
    clicked = QtCore.Signal(QtCore.QModelIndex)

    def __init__(self, json_data, parent=None):
        super(crumbsNavigation, self).__init__(parent)

        self.model =  QtGui.QStandardItemModel(self)
        dict_to_model(self.model.invisibleRootItem(), json_data)
        it = self.model.item(0, 0)
        ix = self.model.indexFromItem(it)

    @QtCore.Slot(QtCore.QModelIndex)
    def on_clicked(self, index):
        if not self.model.hasChildren(index):
            self.clicked.emit(index)
            return
        action = self.toolbar.addAction(index.data())
        action.setData(QtCore.QPersistentModelIndex(index))
        self.listview.setRootIndex(index)

    @QtCore.Slot(QtWidgets.QAction)
    def on_actionTriggered(self, action):
        ix = action.data()
        model = ix.model()
        self.listview.setRootIndex(QtCore.QModelIndex(ix))
        self.toolbar.clear()
        ixs = []
        while  ix.isValid():
            ixs.append(ix)
            ix = ix.parent()
        for ix in reversed(ixs):
            action = self.toolbar.addAction(ix.data())
            action.setData(ix)

    @QtCore.Slot()
    def on_buttonTriggered(self):
        print('Toolbutton Triggered')

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    engine = QtQml.QQmlApplicationEngine()
    crumbObject = crumbsNavigation(crumbs_data)
    engine.rootContext().setContextProperty("crumbsNavigation", crumbObject)
    engine.load(QtCore.QUrl.fromLocalFile('E:/Tech/main.qml'))
    if not engine.rootObjects():
        sys.exit(-1)
    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

enter image description here


Tags: textimportselfdatamodelactionwidthcolor
1条回答
网友
1楼 · 发布于 2024-10-02 22:23:27

qtl中的逻辑在Qt小部件中是相同的,但不具有相同的元素,因为例如QAction和QToolBar都不存在于QML中。你知道吗

我将把逻辑总结如下:

  • 当按下视图或工具栏/QToolBar中的项时,必须更新视图的根索引(ListView/QListView)。

  • 工具栏/QToolBar项必须是rootIndex及其父项。

另一方面,ListView不允许像QListView那样建立根索引,因此要实现相同的功能,必须使用DelegateModel。你知道吗

在python方面,我实现了一个处理导航的类,该类具有以下属性:

  • 模型:它以分层的方式拥有信息。你知道吗
  • 标题:它包含文本信息和工具栏的QModelIndex。你知道吗
  • 根索引。你知道吗

主.py

from PySide2 import QtCore, QtGui, QtWidgets, QtQml


crumbs_data = # ...

def dict_to_model(item, d):
    if isinstance(d, dict):
        for k, v in d.items():
            it = QtGui.QStandardItem(k)
            item.appendRow(it)
            dict_to_model(it, v)
    elif isinstance(d, list):
        for v in d:
            dict_to_model(item, v)
    else:
        item.appendRow(QtGui.QStandardItem(str(d)))


class NavigationManager(QtCore.QObject):
    headersChanged = QtCore.Signal()
    rootIndexChanged = QtCore.Signal("QModelIndex")

    def __init__(self, json_data, parent=None):
        super().__init__(parent)

        self.m_model = QtGui.QStandardItemModel(self)
        dict_to_model(self.m_model.invisibleRootItem(), json_data)

        self.m_headers = []
        self.m_rootindex = QtCore.QModelIndex()
        self.rootIndexChanged.connect(self._update_headers)

        self.rootIndex = self.m_model.index(0, 0)

    def _update_headers(self, ix):
        self.m_headers = []
        while ix.isValid():
            self.m_headers.insert(0, [ix, ix.data()])
            ix = ix.parent()
        self.headersChanged.emit()

    @QtCore.Property(QtCore.QObject, constant=True)
    def model(self):
        return self.m_model

    @QtCore.Property("QVariantList", notify=headersChanged)
    def headers(self):
        return self.m_headers

    def get_root_index(self):
        return self.m_rootindex

    def set_root_index(self, ix):
        if self.m_rootindex != ix:
            self.m_rootindex = ix
            self.rootIndexChanged.emit(ix)

    rootIndex = QtCore.Property(
        "QModelIndex", fget=get_root_index, fset=set_root_index, notify=rootIndexChanged
    )


if __name__ == "__main__":
    import os
    import sys

    navigation_manager = NavigationManager(crumbs_data)

    model = QtGui.QStandardItemModel()
    app = QtWidgets.QApplication(sys.argv)
    engine = QtQml.QQmlApplicationEngine()
    engine.rootContext().setContextProperty("navigation_manager", navigation_manager)
    current_dir = os.path.dirname(os.path.realpath(__file__))
    filename = os.path.join(current_dir, "main.qml")
    engine.load(QtCore.QUrl.fromLocalFile(filename))
    if not engine.rootObjects():
        sys.exit(-1)
    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

主.qml

import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQml.Models 2.13

ApplicationWindow {
    id: mainWindowId
    visible: true
    width: 960
    height: 540
    title: qsTr("Breadcrumbs Test")

    Rectangle {
        width: parent.width
        height: parent.height

        ColumnLayout {
            width: parent.width
            height: parent.height
            spacing: 6

            TextField {
                id: filterTextFieldId
                Layout.fillWidth: true
                Layout.preferredHeight: 40
                font {
                    family: "SF Pro Display"
                 pixelSize: 22
                }
                placeholderText: "Type Filter Expression"
                color: "dodgerblue"
            }

            ToolBar {
                background: Rectangle {
                    color: "transparent"
                }
                RowLayout {
                    anchors.fill: parent
                    spacing: 10
                    Repeater{
                        model: navigation_manager.headers
                        ToolButton {
                            Layout.preferredHeight: 20
                            contentItem: Text {
                                text: model.modelData[1]
                                color: "#FFFFFF"
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                            }
                            background: Rectangle {
                                radius: 12
                                color:  "#40e0d0"
                            }
                            onClicked: navigation_manager.rootIndex = model.modelData[0]
                        }
                    }
                }
            }
            Rectangle {
                Layout.fillWidth: true
                Layout.fillHeight: true
                color: "dodgerblue"

                ListView{
                    id: view
                    anchors.fill: parent
                    anchors.margins: 12
                    model: DelegateModel {
                        model: navigation_manager.model
                        rootIndex: navigation_manager.rootIndex
                        delegate: Rectangle {
                            height: 25
                            color:"transparent"
                            Text { 
                                text: model.display
                                color:"white"
                                MouseArea{
                                    anchors.fill: parent
                                    onClicked: {
                                        if (model.hasModelChildren)
                                            navigation_manager.rootIndex = view.model.modelIndex(index)
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

相关问题 更多 >