python - 使用 QToolBar 和 QListView 进行面包屑导航

标签 python pyside2 qlistview qtoolbar

我有类似这样的 JSON 数据

{"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"]
}}}}

现在我想使用 QAbstractListModelQToolBar 作为面包屑导航 (QAction) 在 QListView 中填充这些数据。 QListView 将随着用户更新 触发键。那么我该如何实现呢?

breadcrumbs
(来源:gifyu.com)

最佳答案

第一件事是将 json 转换为模型,在本例中使用 QStandardItemModel。然后我们在 QListView 中使用该模型,使用 setRootIndex() 来指示将显示的项目,另一方面将 QActions 添加到使用父树的 QToolBar

from PyQt5 import QtCore, QtGui, QtWidgets

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 Navigation(QtCore.QObject):
    clicked = QtCore.pyqtSignal(QtCore.QModelIndex)
    def __init__(self, json_data, parent=None):
        super(Navigation, self).__init__(parent)
        self.toolbar = QtWidgets.QToolBar()
        self.toolbar.actionTriggered.connect(self.on_actionTriggered)
        self.model =  QtGui.QStandardItemModel(self)
        dict_to_model(self.model.invisibleRootItem(), json_data)
        it = self.model.item(0, 0)
        ix = self.model.indexFromItem(it)
        root_action = self.toolbar.addAction(it.text())
        root_action.setData(QtCore.QPersistentModelIndex(ix))
        self.listview = QtWidgets.QListView()
        self.listview.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.listview.clicked.connect(self.on_clicked)
        self.listview.setModel(self.model)
        self.listview.setRootIndex(ix)

    @QtCore.pyqtSlot(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.pyqtSlot(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)

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        navigation = Navigation(data, self)
        navigation.clicked.connect(self.on_clicked)

        tree_view = QtWidgets.QTreeView()
        tree_view.setModel(navigation.model)
        navigation.model.setHorizontalHeaderLabels(["Tree Example"])
        tree_view.expandAll()

        self.addToolBar(navigation.toolbar)

        widget = QtWidgets.QWidget()
        self.setCentralWidget(widget)
        lay = QtWidgets.QHBoxLayout(widget)
        lay.addWidget(navigation.listview)
        lay.addWidget(tree_view)

    @QtCore.pyqtSlot(QtCore.QModelIndex)
    def on_clicked(self, index):
        print(index.data())

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

关于python - 使用 QToolBar 和 QListView 进行面包屑导航,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53022651/

相关文章:

python - 使用 backref "length"和 SQLAlchemy 进行过滤的方法

python - 如何部署pyside2应用程序? -Qt方式

c++ - Qt 的 ItemViewsNG 项目的状态如何?

qt - 带有自定义项目和自定义项目小部件的 QListView/QListWidget

c++ - qt QStandardItemModel 数据()未被调用

python - Pandas 移动行值以匹配列名

c++ - 是否有即时编译的正则表达式引擎?

python - 如何在 PyQt 中绘制自定义椭圆形?

python - 读取 UI 文件并连接按钮、文本等元素

python - 如何将函数传递给 Python 中的函数?