(PyQt) QTreeView - 想要展开/折叠所有子级和孙级
我希望能够展开或折叠 QTreeView 中特定分支的所有子级。我正在使用 PyQt4。
我知道 QTreeView 有一个绑定到 * 的展开所有子项功能,但我需要两件事:它需要绑定到不同的组合键(shift-space),而且我还需要能够折叠所有子项。
这是我到目前为止所尝试过的: 我有一个 QTreeView 的子类,其中我正在检查 Shift-Space 键组合。我知道 QModelIndex 会让我使用“child”函数选择一个特定的子项,但这需要知道子项的数量。我能够通过查看internalPointer来获取子级的计数,但这只能提供层次结构第一级的信息。如果我尝试使用递归,我可以获得一堆子计数,但随后我不知道如何将它们转换回有效的 QModelIndex。
这是一些代码:
def keyPressEvent(self, event):
"""
Capture key press events to handle:
- enable/disable
"""
#shift - space means toggle expanded/collapsed for all children
if (event.key() == QtCore.Qt.Key_Space and
event.modifiers() & QtCore.Qt.ShiftModifier):
expanded = self.isExpanded(self.selectedIndexes()[0])
for cellIndex in self.selectedIndexes():
if cellIndex.column() == 0: #only need to call it once per row
#I can get the actual object represented here
item = cellIndex.internalPointer()
#and I can get the number of children from that
numChildren = item.get_child_count()
#but now what? How do I convert this number into valid
#QModelIndex objects? I know I could use:
# cellIndex.child(row, 0)
#to get the immediate children's QModelIndex's, but how
#would I deal with grandchildren, great grandchildren, etc...
self.setExpanded(cellIndex, not(expanded))
return
这是我正在研究的递归方法的开始,但是当实际尝试设置扩展状态时我陷入困境,因为一旦进入递归,我就失去了与任何有效的 QModelIndex 的“联系”......
def toggle_expanded(self, item, expand):
"""
Toggles the children of item (recursively)
"""
for row in range(0,item.get_child_count()):
newItem = item.get_child_at_row(row)
self.toggle_expanded(newItem, expand)
#well... I'm stuck here because I'd like to toggle the expanded
#setting of the "current" item, but I don't know how to convert
#my pointer to the object represented in the tree view back into
#a valid QModelIndex
#self.setExpanded(?????, expand) #<- What I'd like to run
print "Setting", item.get_name(), "to", str(expand) #<- simple debug statement that indicates that the concept is valid
感谢所有人花时间看看这个!
I want to be able to expand or collapse all children of a particular branch in a QTreeView. I am using PyQt4.
I know that QTreeView's have an expand all children feature that is bound to *, but I need two things: It needs to be bound to a different key combination (shift-space) and I also need to be able to collapse all children as well.
Here is what I have tried so far:
I have a subclass of a QTreeView wherein I am checking for the shift-space key combo. I know that QModelIndex will let me pick a specific child with the "child" function, but that requires knowing the number of children. I am able to get a count of the children by looking at the internalPointer, but that only gives me info for the first level of the hierarchy. If I try to use recursion, I can get a bunch of child counts, but then I am lost as to how to get these converted back into a valid QModelIndex.
Here is some code:
def keyPressEvent(self, event):
"""
Capture key press events to handle:
- enable/disable
"""
#shift - space means toggle expanded/collapsed for all children
if (event.key() == QtCore.Qt.Key_Space and
event.modifiers() & QtCore.Qt.ShiftModifier):
expanded = self.isExpanded(self.selectedIndexes()[0])
for cellIndex in self.selectedIndexes():
if cellIndex.column() == 0: #only need to call it once per row
#I can get the actual object represented here
item = cellIndex.internalPointer()
#and I can get the number of children from that
numChildren = item.get_child_count()
#but now what? How do I convert this number into valid
#QModelIndex objects? I know I could use:
# cellIndex.child(row, 0)
#to get the immediate children's QModelIndex's, but how
#would I deal with grandchildren, great grandchildren, etc...
self.setExpanded(cellIndex, not(expanded))
return
Here is the beginning of the recursion method I was investigating, but I get stuck when actually trying to set the expanded state because once inside the recursion, I lose "contact" with any valid QModelIndex...
def toggle_expanded(self, item, expand):
"""
Toggles the children of item (recursively)
"""
for row in range(0,item.get_child_count()):
newItem = item.get_child_at_row(row)
self.toggle_expanded(newItem, expand)
#well... I'm stuck here because I'd like to toggle the expanded
#setting of the "current" item, but I don't know how to convert
#my pointer to the object represented in the tree view back into
#a valid QModelIndex
#self.setExpanded(?????, expand) #<- What I'd like to run
print "Setting", item.get_name(), "to", str(expand) #<- simple debug statement that indicates that the concept is valid
Thanks to all for taking the time to look at this!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧……兄弟姐妹实际上并没有把我带到我想去的地方。我设法让代码按如下方式工作(这似乎是一个不错的实现)。仍然要感谢 Ebral 教授,他让我沿着兄弟姐妹的想法走上了正确的道路(事实证明我需要使用 QModelIndex.child(row, column) 并从那里递归迭代)。
请注意,代码中有以下假设:它假设您的基础数据存储对象能够报告它们有多少个子对象(在我的代码中为 get_child_count() )。如果不是这种情况,您将不得不以不同的方式获得子计数...也许只是任意尝试获取子索引 - 使用 QModelIndex.child(row, col) - 行数不断增加直到您返回无效索引? - 这是 Ebral 教授的建议,我可能仍然会尝试(只是我已经有了一种简单的方法来通过从我的数据存储请求来获取子计数)。
另请注意,我实际上根据是展开还是折叠在递归中的不同点展开/折叠每个节点。这是因为,通过反复试验,我发现如果我只在代码中的一处执行动画树视图,动画树视图就会卡顿和弹出。现在,通过根据我是否位于顶层(即我正在影响的分支的根 - 而不是整个树视图的根)来反转我执行此操作的顺序,我得到了一个非常流畅的动画。这在下面有记录。
以下代码位于 QTreeView 子类中。
Ok... siblings did not actually get me to where I wanted to go. I managed to get the code working as follows (and it seems like a decent implementation). Kudos still to Prof.Ebral who got me going on the right track with the idea of siblings (turns out I needed to use QModelIndex.child(row, column) and iterate recursively from there).
Note that there is the following assumption in the code: It assumes that your underlying data store objects have the ability to report how many children they have (get_child_count() in my code). If that is not the case, you will somehow have to get a child count differently... perhaps by just arbitrarily trying to get child indexes - using QModelIndex.child(row, col) - with an ever increasing row count till you get back an invalid index? - this is what Prof.Ebral suggested and I might still try that (It is just that I already have an easy way to get the child count by requesting it from my data store).
Also note that I actually expand/collpase each node at a different point in the recursion based on whether I am expanding or collapsing. This is because, through trial and error, I discovered that animated tree views would stutter and pop if I just did it at one place in the code. Now, by reversing the order in which I do it based on whether I am at the top level (i.e. the root of the branch I am affecting - not the root of the entire treeview) I get a nice smooth animation. This is documented below.
The following code is in a QTreeView subclass.
model.rowCount(index) 是您想要的方法。
model.index(row,col,parent)本质上与调用index.child(row,col)相同;只是用更少的间接方式。
model.rowCount(index) is the method you want.
model.index(row,col, parent) is essentially the same as calling index.child(row,col); just with fewer indirections.
我建议使用继承QTreeView的QTreeWidget。然后,您可以将子项作为 QTreeWidgetItem 获取。由于您不想使用 QTreeWidget 但想坚持使用当前模型..您可以使用 .isValid() 迭代“可能的”子项。不过,您不应该使用internalPointer()。相反,使用您拥有的 cellItem,因为它是原始的 ModalIndex .. 然后尝试找到它的兄弟姐妹。像这样的东西
I would recommend using a QTreeWidget which inherits QTreeView. You can then grab the children as a QTreeWidgetItem.Since you do not want to use the QTreeWidget but want to stick to your current model .. you can iterate through the 'possible' children using, .isValid(). You should not use the internalPointer() though. Instead use the cellItem you have, as it is the original ModalIndex .. then attempt to find it's siblings. Something like
我为此创建了一个 evnetFilter 类。
我的特定用例是按住 Shift 键并单击放置指示器,然后展开所有或折叠所有子节点,例如软件
maya
大纲视图。下面的用法示例
gif 示例
I make a evnetFilter Class for that.
My particular use case is shift click the drop indicator then expand all or collapse all the child nodes like software
maya
outliner.Usage Example below
example gif