2

QTreeViewの特定のブランチのすべての子を展開または折りたたむことができるようにしたいと思います。私はPyQt4を使用しています。

QTreeViewには*にバインドされたすべての子の展開機能があることは知っていますが、2つのことが必要です。別のキーの組み合わせ(シフトスペース)にバインドする必要があり、すべての子も折りたたむことができる必要があります。 。

これまでに試したことは次のとおりです。QTreeViewのサブクラスがあり、シフトスペースキーの組み合わせをチェックしています。QModelIndexで「子」関数を使用して特定の子を選択できることは知っていますが、それには子の数を知る必要があります。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

これを見てくれてありがとう!

4

4 に答える 4

4

わかりました...兄弟は実際に私が行きたい場所に私を連れて行ってくれませんでした。私はなんとかコードを次のように機能させることができました(そしてそれはまともな実装のようです)。兄弟のアイデアで私を正しい軌道に乗せてくれたEbral教授には、今でも称賛があります(QModelIndex.child(row、column)を使用し、そこから再帰的に繰り返す必要がありました)。

コードには次の仮定があることに注意してください。基礎となるデータストアオブジェクトには、子の数を報告する機能があることを前提としています(私のコードではget_child_count())。そうでない場合は、どういうわけか、子の数を別の方法で取得する必要があります...おそらく、QModelIndex.child(row、col)を使用して、子のインデックスを任意に取得しようとします。無効なインデックス?-これはProf.Ebralが提案したことであり、私はまだそれを試すかもしれません(データストアから要求することで、子の数を取得する簡単な方法がすでにあるというだけです)。

また、拡張するか折りたたみするかに基づいて、再帰の異なるポイントで各ノードを実際に拡張/折りたたみすることにも注意してください。これは、試行錯誤の結果、コード内の1つの場所で実行すると、アニメーション化されたツリービューが途切れたりポップしたりすることを発見したためです。これで、トップレベルにいるかどうか(つまり、影響を与えているブランチのルート-ツリービュー全体のルートではない)に基づいて順序を逆にすることで、スムーズなアニメーションが得られます。これは以下に文書化されています。

次のコードはQTreeViewサブクラスにあります。

#---------------------------------------------------------------------------
def keyPressEvent(self, event):

    if (event.key() == QtCore.Qt.Key_Space and self.currentIndex().column() == 0):
        shift = event.modifiers() & QtCore.Qt.ShiftModifier
        if shift:
            self.expand_all(self.currentIndex())
        else:                
            expand = not(self.isExpanded(self.currentIndex()))
            self.setExpanded(self.currentIndex(), expand)


#---------------------------------------------------------------------------
def expand_all(self, index):
    """
    Expands/collapses all the children and grandchildren etc. of index.
    """
    expand = not(self.isExpanded(index))
    if not expand: #if collapsing, do that first (wonky animation otherwise)
        self.setExpanded(index, expand)    
    childCount = index.internalPointer().get_child_count()
    self.recursive_expand(index, childCount, expand)
    if expand: #if expanding, do that last (wonky animation otherwise)
        self.setExpanded(index, expand)


#---------------------------------------------------------------------------
def recursive_expand(self, index, childCount, expand):
    """
    Recursively expands/collpases all the children of index.
    """
    for childNo in range(0, childCount):
        childIndex = index.child(childNo, 0)
        if expand: #if expanding, do that first (wonky animation otherwise)
            self.setExpanded(childIndex, expand)
        subChildCount = childIndex.internalPointer().get_child_count()
        if subChildCount > 0:
            self.recursive_expand(childIndex, subChildCount, expand)
        if not expand: #if collapsing, do it last (wonky animation otherwise)
            self.setExpanded(childIndex, expand)
于 2010-11-17T19:20:30.560 に答える
2

model.rowCount(index)は必要なメソッドです。

model = index.model()   # or some other way of getting it
for i in xrange(model.rowCount(index)):
  child = model.index(i,0, index)
  # do something with child

model.index(row、col、parent)は、基本的にindex.child(row、col);を呼び出すのと同じです。間接的な数が少ないだけです。

于 2011-02-15T02:05:18.893 に答える
1

QTreeViewを継承するQTreeWidgetの使用をお勧めします。次に、子をQTreeWidgetItemとして取得できます。

QTreeWidgetを使用したくないが、現在のモデルに固執したいので、.isValid()を使用して「可能な」子を反復処理できます。ただし、internalPointer()は使用しないでください。代わりに、元のModalIndexであるため、所有しているcellItemを使用して、兄弟を見つけようとします。何かのようなもの

x = 0; y =0
while cellIndex.sibling(x, y).isValid():
    child = cellIndex.sibling(x, y)
    x += 1
于 2010-11-09T05:37:05.670 に答える
1

そのためにevnetFilterクラスを作成します。私の特定のユースケースは、ドロップインジケーターをShiftキーを押しながらクリックしてから、ソフトウェアアウトライナーのように、すべてを展開するか、すべての子ノードを折りたたむことmayaです。


class MTreeExpandHook(QtCore.QObject):
    """
    MTreeExpandHook( QTreeView )
    """

    def __init__(self, tree):
        super(MTreeExpandHook, self).__init__()
        tree.viewport().installEventFilter(self)
        self.tree = tree

    def eventFilter(self, receiver, event):
        if (
            event.type() == QtCore.QEvent.Type.MouseButtonPress
            and event.modifiers() & QtCore.Qt.ShiftModifier
        ):
            pos = self.tree.mapFromGlobal(QtGui.QCursor.pos())
            index = self.tree.indexAt(pos)
            if not self.tree.isExpanded(index):
                self.tree.expandRecursively(index)
                return True
        return super(MTreeExpandHook, self).eventFilter(self.tree, event)

以下の使用例


import sys
from PySide2 import QtCore,QtGui,QtWidgets

class MTreeExpandHook(QtCore.QObject):
    """
    MTreeExpandHook( QTreeView )
    """

    def __init__(self, tree):
        super(MTreeExpandHook, self).__init__()
        self.setParent(tree)
        # NOTE viewport for click event listen
        tree.viewport().installEventFilter(self)
        self.tree = tree

    def eventFilter(self, receiver, event):
        if (
            # NOTE mouse left click 
            event.type() == QtCore.QEvent.Type.MouseButtonPress
            # NOTE keyboard shift press
            and event.modifiers() & QtCore.Qt.ShiftModifier
        ):
            # NOTE get mouse local position
            pos = self.tree.mapFromGlobal(QtGui.QCursor.pos())
            index = self.tree.indexAt(pos)
            if not self.tree.isExpanded(index):
                # NOTE expand all child
                self.tree.expandRecursively(index)
                return True
        return super(MTreeExpandHook, self).eventFilter(self.tree, event)
    

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    
    model = QtGui.QStandardItemModel()
    
    # NOTE create nested data
    for i in range(3):
        parent = QtGui.QStandardItem('Family {}'.format(i))
        for j in range(3):
            child = QtGui.QStandardItem('Child {}'.format(i*3+j))
            for k in range(3):
                sub_child = QtGui.QStandardItem("Sub Child")
                child.appendRow([sub_child])
                for x in range(2):
                    sub_child_2 = QtGui.QStandardItem("Sub Child 2")
                    sub_child.appendRow([sub_child_2])
            parent.appendRow([child])
        model.appendRow(parent)

        
    treeView = QtWidgets.QTreeView()
    treeView.setHeaderHidden(True)
    MTreeExpandHook(treeView)
    treeView.setModel(model)
    treeView.show()
    
    sys.exit(app.exec_())

gifの例

于 2021-07-14T05:05:07.023 に答える