QAbstractItemModel:QTreeView 中烦人的分支线
QAbstractItemModel: annoying branch line in QTreeView
我制作了 QAbstractItemModel
的简约子类。它有效,但在 QTreeView 中有一条不应该出现在这里的奇怪分支线(因为 [Sensor arrays] 部分之后没有更多项目)。你能告诉我,我做错了什么以及如何解决吗?
这是我的代码:
import os, sys
from PyQt5 import QtCore, QtGui, QtWidgets
import treelib
class BlockHierarchyNode(object):
def __init__(self, icon_path=None, name="", description="", is_category=False):
if icon_path is not None:
self._icon = QtGui.QPixmap(icon_path)
if self._icon.size() == QtCore.QSize(): # zero size (loading error)
assert False
else:
self._icon = None
self._is_category = bool(is_category)
self._name = str(name)
self._description = str(description)
@property
def icon(self):
return self._icon
@property
def is_category(self):
return self._is_category
@property
def name(self):
return self._name
@property
def description(self):
return self._description
def __str__(self):
if self.is_category:
return "[%s]" % self.name
else:
return self.name
class AvailableBlocksModel(QtCore.QAbstractItemModel):
def __init__(self, data_tree, parent=None):
super(AvailableBlocksModel, self).__init__(parent)
self._tree = data_tree
assert isinstance(data_tree, treelib.Tree)
def columnCount(self, parent_index):
if parent_index.isValid():
return 1
else:
return 1
def rowCount(self, parent_index):
if parent_index.isValid():
return len(self._tree.children(parent_index.internalPointer().identifier))
else: # root node
return 1
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.DisplayRole:
return str(index.internalPointer().data)
elif role == QtCore.Qt.DecorationRole:
icon = index.internalPointer().data.icon
if icon is not None:
return icon
return None
def index(self, row, column, parent=QtCore.QModelIndex()):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
if parent.isValid():
parent_node = parent.internalPointer()
children = self._tree.children(parent_node.identifier)
return self.createIndex(row, column, children[row])
else:
return self.createIndex(row, column, self._tree.nodes[self._tree.root])
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
child_item = index.internalPointer()
parent_item = self._tree.parent(child_item.identifier)
if parent_item is None:
return QtCore.QModelIndex()
parent_row = 0
siblings = self._tree.siblings(parent_item.identifier)
for i, elm in enumerate(siblings):
if elm == parent_item:
parent_row = i
return self.createIndex(parent_row, 0, parent_item)
class MegaTree(treelib.Tree):
def add_block_node(self, data_block, identifier=None, parent_node=None):
id = identifier if identifier is not None else data_block.name
if parent_node is None:
return self.create_node(str(data_block), id, data=data_block)
else:
return self.create_node(str(data_block), id, data=data_block, parent=parent_node.identifier)
@staticmethod
def create_demo_tree():
tree = MegaTree()
root_data = BlockHierarchyNode(name="All blocks", is_category=True)
root_node = tree.add_block_node(root_data, "root") # root node
waveforms_data = BlockHierarchyNode(name="Waveforms", is_category=True)
waveforms_node = tree.add_block_node(waveforms_data, parent_node=root_node)
rect_waveform_data = BlockHierarchyNode(name="Rectangular waveform", is_category=False)
rect_waveform_node = tree.add_block_node(rect_waveform_data, parent_node=waveforms_node)
lfm_waveform_data = BlockHierarchyNode(name="LFM waveform", is_category=False)
lfm_waveform_node = tree.add_block_node(lfm_waveform_data, parent_node=waveforms_node)
phasecoded_waveform_data = BlockHierarchyNode(name="Phase coded waveform", is_category=False)
phasecoded_waveform_node = tree.add_block_node(phasecoded_waveform_data, parent_node=waveforms_node)
sensor_array_data = BlockHierarchyNode(name="Sensor arrays", is_category=True)
sensor_array_node = tree.add_block_node(sensor_array_data, parent_node=root_node)
ura_data = BlockHierarchyNode(name="URA", is_category=False)
ura_node = tree.add_block_node(ura_data, parent_node=sensor_array_node)
ula_data = BlockHierarchyNode(name="ULA", is_category=False)
ula_node = tree.add_block_node(ula_data, parent_node=sensor_array_node)
return tree
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
model = AvailableBlocksModel(MegaTree.create_demo_tree())
view = QtWidgets.QTreeView()
view.setModel(model)
view.expandAll()
view.show()
sys.exit(app.exec_())
哦,我刚刚忘记了 Tree
class 的 treelib
的 siblings
方法严格地给出了一个节点的兄弟节点(没有节点本身在名单)。因此,在 parent
方法中,它的行始终为 0。 = (
方法在这里:
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
child_item = index.internalPointer()
parent_item = self._tree.parent(child_item.identifier)
if parent_item is None:
return QtCore.QModelIndex()
if parent_item.is_root():
parent_row = 0
else:
siblings = self._tree.children(parent_item.bpointer)
for i, elm in enumerate(siblings):
if elm == parent_item:
parent_row = i
我制作了 QAbstractItemModel
的简约子类。它有效,但在 QTreeView 中有一条不应该出现在这里的奇怪分支线(因为 [Sensor arrays] 部分之后没有更多项目)。你能告诉我,我做错了什么以及如何解决吗?
这是我的代码:
import os, sys
from PyQt5 import QtCore, QtGui, QtWidgets
import treelib
class BlockHierarchyNode(object):
def __init__(self, icon_path=None, name="", description="", is_category=False):
if icon_path is not None:
self._icon = QtGui.QPixmap(icon_path)
if self._icon.size() == QtCore.QSize(): # zero size (loading error)
assert False
else:
self._icon = None
self._is_category = bool(is_category)
self._name = str(name)
self._description = str(description)
@property
def icon(self):
return self._icon
@property
def is_category(self):
return self._is_category
@property
def name(self):
return self._name
@property
def description(self):
return self._description
def __str__(self):
if self.is_category:
return "[%s]" % self.name
else:
return self.name
class AvailableBlocksModel(QtCore.QAbstractItemModel):
def __init__(self, data_tree, parent=None):
super(AvailableBlocksModel, self).__init__(parent)
self._tree = data_tree
assert isinstance(data_tree, treelib.Tree)
def columnCount(self, parent_index):
if parent_index.isValid():
return 1
else:
return 1
def rowCount(self, parent_index):
if parent_index.isValid():
return len(self._tree.children(parent_index.internalPointer().identifier))
else: # root node
return 1
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.DisplayRole:
return str(index.internalPointer().data)
elif role == QtCore.Qt.DecorationRole:
icon = index.internalPointer().data.icon
if icon is not None:
return icon
return None
def index(self, row, column, parent=QtCore.QModelIndex()):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
if parent.isValid():
parent_node = parent.internalPointer()
children = self._tree.children(parent_node.identifier)
return self.createIndex(row, column, children[row])
else:
return self.createIndex(row, column, self._tree.nodes[self._tree.root])
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
child_item = index.internalPointer()
parent_item = self._tree.parent(child_item.identifier)
if parent_item is None:
return QtCore.QModelIndex()
parent_row = 0
siblings = self._tree.siblings(parent_item.identifier)
for i, elm in enumerate(siblings):
if elm == parent_item:
parent_row = i
return self.createIndex(parent_row, 0, parent_item)
class MegaTree(treelib.Tree):
def add_block_node(self, data_block, identifier=None, parent_node=None):
id = identifier if identifier is not None else data_block.name
if parent_node is None:
return self.create_node(str(data_block), id, data=data_block)
else:
return self.create_node(str(data_block), id, data=data_block, parent=parent_node.identifier)
@staticmethod
def create_demo_tree():
tree = MegaTree()
root_data = BlockHierarchyNode(name="All blocks", is_category=True)
root_node = tree.add_block_node(root_data, "root") # root node
waveforms_data = BlockHierarchyNode(name="Waveforms", is_category=True)
waveforms_node = tree.add_block_node(waveforms_data, parent_node=root_node)
rect_waveform_data = BlockHierarchyNode(name="Rectangular waveform", is_category=False)
rect_waveform_node = tree.add_block_node(rect_waveform_data, parent_node=waveforms_node)
lfm_waveform_data = BlockHierarchyNode(name="LFM waveform", is_category=False)
lfm_waveform_node = tree.add_block_node(lfm_waveform_data, parent_node=waveforms_node)
phasecoded_waveform_data = BlockHierarchyNode(name="Phase coded waveform", is_category=False)
phasecoded_waveform_node = tree.add_block_node(phasecoded_waveform_data, parent_node=waveforms_node)
sensor_array_data = BlockHierarchyNode(name="Sensor arrays", is_category=True)
sensor_array_node = tree.add_block_node(sensor_array_data, parent_node=root_node)
ura_data = BlockHierarchyNode(name="URA", is_category=False)
ura_node = tree.add_block_node(ura_data, parent_node=sensor_array_node)
ula_data = BlockHierarchyNode(name="ULA", is_category=False)
ula_node = tree.add_block_node(ula_data, parent_node=sensor_array_node)
return tree
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
model = AvailableBlocksModel(MegaTree.create_demo_tree())
view = QtWidgets.QTreeView()
view.setModel(model)
view.expandAll()
view.show()
sys.exit(app.exec_())
哦,我刚刚忘记了 Tree
class 的 treelib
的 siblings
方法严格地给出了一个节点的兄弟节点(没有节点本身在名单)。因此,在 parent
方法中,它的行始终为 0。 = (
方法在这里:
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
child_item = index.internalPointer()
parent_item = self._tree.parent(child_item.identifier)
if parent_item is None:
return QtCore.QModelIndex()
if parent_item.is_root():
parent_row = 0
else:
siblings = self._tree.children(parent_item.bpointer)
for i, elm in enumerate(siblings):
if elm == parent_item:
parent_row = i