【问题标题】:QStandardItemModel doesn't emit rowsMoved() signal on QTreeView InternalMoveQStandardItemModel 不会在 QTreeView InternalMove 上发出 rowsMo​​ved() 信号
【发布时间】:2020-07-28 15:48:45
【问题描述】:

我有一个由QStandardItemModel 填充的QTreeView,并设置了TreeView,因此它只允许内部拖放(InternalMove)。 我试图检测用户何时进行此类内部移动并希望提取被拖动的项目以及开始和结束位置。

QStandardItemModel 提供了“rowsMoved”信号,它应该准确地发出我正在寻找的东西:父、开始、结束、目的地、行。 问题:在物品周围移动时,这个信号永远不会被调用。这是为什么呢?

rowsInserted()rowsRemoved() 等其他信号可以正常工作,但 rowsMoved() 不能。

在以下最小示例中,onMove() 中的 print() 应该在用户在项目周围移动时调用,但它不会。

import random
import sys

from PyQt5 import QtCore, QtGui, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        model = QtGui.QStandardItemModel(self)

        view = QtWidgets.QTreeView()

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(view)

        view.setModel(model)

        root_item = QtGui.QStandardItem("Root")
        model.appendRow(root_item)

        self.populate(root_item, 3)
        view.expandAll()

        view.setDragEnabled(True)
        view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
        view.setDefaultDropAction(QtCore.Qt.MoveAction)
        view.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems)
        model.rowsMoved.connect(self.onMove)  
    
    def onMove(self, parent, start, end, destination, row):
        print("parent",parent,"start",start,"end",end,"destination",destination,"row",row)

    def populate(self, root_item, level):
        for i in range(random.randint(2, 4)):
            it = QtGui.QStandardItem("item {}".format(i))
            it.setCheckable(False)
            root_item.appendRow(it)
            next_level = level - 1
            if next_level > 0:
                self.populate(it, next_level)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    w = Widget()
    w.show()

    sys.exit(app.exec_())

【问题讨论】:

  • 你为什么要删除你之前的帖子并用相同的信息重新发布?这很烦人,可以被认为是噪音。你在滥用系统
  • 对不起!我不得不多次编辑之前的帖子,并认为我会以正确的形式重新发布它。
  • 不,系统的创建是为了让 OP 在需要时进行大量编辑。很多时候,一些 OP 认为转发会得到更多积极的关注,但事实是他们得到了相反的结果。我更喜欢看到一个包含许多版本的 OP 的帖子,表明他已经在他的帖子上工作过,而不是嘈杂的转发。
  • 好吧抱歉,以后不会这样了!

标签: python pyqt5 qtreeview qstandarditemmodel


【解决方案1】:

文档说明:

Components connected to this signal use it to adapt to changes
in the model's dimensions. It can only be emitted by the QAbstractItemModel
implementation, and cannot be explicitly emitted in subclass code.

考虑到这个信号不是由QStandardItemModel 类定义的,这个类的任何实例都不会发出这样的信号。 正如您所提到的,您可以连接的唯一信号是rowsInserted()rowsRemoved(),因为它们在此类中被重新定义。请注意,它们在源文件中标记为internal

如果您需要有关被拖动项目的信息,我建议您创建一个继承自 QtWidgets.QTreeView 的自定义类并覆盖 dragEnterEventdropEvent 方法。

这是一个示例,说明如何通过拖放整个层次结构来检索项目:

import random
import sys

from PyQt5 import QtCore, QtGui, QtWidgets


def getHierarchy(index, hierarchy=None):
    hierarchy = hierarchy or []
    if not index.isValid():
        return hierarchy
    hierarchy.insert(0, (index.row(), index.column()))
    return getHierarchy(index.parent(), hierarchy)


class MyTreeView(QtWidgets.QTreeView):

    def dropEvent(self, e):
        super().dropEvent(e)
        currentIndex = e.source().currentIndex()
        print('dropEvent.source current index:', getHierarchy(currentIndex))

    def dragEnterEvent(self, e):
        super().dragEnterEvent(e)
        currentIndex = e.source().currentIndex()
        print('dragEnterEvent.source current index:', getHierarchy(currentIndex))


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        model = QtGui.QStandardItemModel(self)

        view = MyTreeView()

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(view)

        view.setModel(model)

        root_item = QtGui.QStandardItem("Root")
        model.appendRow(root_item)

        self.populate(root_item, 3)
        view.expandAll()

        view.setDragEnabled(True)
        view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
        view.setDefaultDropAction(QtCore.Qt.MoveAction)
        view.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems)

    def populate(self, root_item, level):
        for i in range(random.randint(2, 4)):
            it = QtGui.QStandardItem("item {}".format(i))
            it.setCheckable(False)
            root_item.appendRow(it)
            next_level = level - 1
            if next_level > 0:
                self.populate(it, next_level)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    w = Widget()
    w.show()

    sys.exit(app.exec_())

我建议查看这个与您处理类似问题的存储库:https://github.com/d1vanov/PyQt5-reorderable-list-model

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 2013-05-12
    • 1970-01-01
    • 2012-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多