使用 QToolBar 和 QListView 的面包屑导航
Breadcrumbs navigation using QToolBar and QListView
我有 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"]
}}}}
现在我想使用 QAbstractListModel
在 QListView
中填充此数据,并使用 QToolBar
作为面包屑导航 (QAction)。 QListView
将更新为用户
触发键。那么我该如何实现呢?
(来源: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_())
我有 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"]
}}}}
现在我想使用 QAbstractListModel
在 QListView
中填充此数据,并使用 QToolBar
作为面包屑导航 (QAction)。 QListView
将更新为用户
触发键。那么我该如何实现呢?
(来源: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_())