首页 > 解决方案 > qtreewidget itemChanged 被调用两次进行重命名

问题描述

我正在制作 QTreeWidget 的子类。

在尝试捕获涉及其默认信号的重命名时 -itemChangeditemDoubleClicked,这些方法确实有效,但我注意到它们itemChanged被调用了两次而不是一次。

无法真正弄清楚第二个“额外”信号的触发位置或原因。

欣赏是否有人可以提供一些启示。

IsNewItemRole = QtCore.Qt.UserRole + 1000


class CustomTreeDelegate(QtGui.QStyledItemDelegate):
    @property
    def text_color(self):
        if not hasattr(self, "_text_color"):
            self._text_color = QtGui.QColor()
        return self._text_color

    @text_color.setter
    def text_color(self, color):
        """Sets QColor towards object.

        Args:
            color (QtGui.QColor): RGB color values.
        """
        self._text_color = color

    def initStyleOption(self, option, index):
        """Change the font color only if item is a new added item.

        Args:
            option ():
            index (QModelIndex?)
        """
        super(CustomTreeDelegate, self).initStyleOption(option, index)
        if self.text_color.isValid() and index.data(IsNewItemRole):
            option.palette.setBrush(QtGui.QPalette.Text, self.text_color)


class CustomTreeWidgetItem(QtGui.QTreeWidgetItem):
    """Initialization class for QTreeWidgetItem creation.

    Args:
        widget (QtGui.QTreeWidget): To append items into.
        text (str): Input name for QTreeWidgetItem.
        is_tristate (bool): Should it be a tri-state checkbox. False by default.
    """
    def __init__(self, parent=None, text=None, is_tristate=False, is_new_item=False):
        super(CustomTreeWidgetItem, self).__init__(parent)

        self.setText(0, text)
        # flags = QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable

        if is_tristate:
            # flags |= QtCore.Qt.ItemIsTristate

            # Solely for the Parent item
            self.setFlags(
                self.flags()
                | QtCore.Qt.ItemIsTristate
                | QtCore.Qt.ItemIsEditable
                | QtCore.Qt.ItemIsUserCheckable
            )
        else:
            self.setFlags(
                self.flags()
                | QtCore.Qt.ItemIsEditable
                | QtCore.Qt.ItemIsUserCheckable
            )
            self.setCheckState(0, QtCore.Qt.Unchecked)

        self.setData(0, IsNewItemRole, is_new_item)

    def setData(self, column, role, value):
        """Override QTreeWidgetItem setData function.

        QTreeWidget does not have a signal that defines when an item has been
        checked/ unchecked. And so, this method will emits the signal as a
        means to handle this.

        Args:
            column (int): Column value of item.
            role (int): Value of Qt.ItemDataRole. It will be Qt.DisplayRole or
                Qt.CheckStateRole
            value (int or unicode): 
        """
        state = self.checkState(column)
        QtGui.QTreeWidgetItem.setData(self, column, role, value)
        if (role == QtCore.Qt.CheckStateRole and
                state != self.checkState(column)):
            tree_widget = self.treeWidget()
            if isinstance(tree_widget, CustomTreeWidget):
                tree_widget.itemToggled.emit(self, column)


class CustomTreeWidget(QtGui.QTreeWidget):
    """Initialization class for QTreeWidget creation.

    Args:
        widget ():
    """
    itemToggled = QtCore.pyqtSignal(QtGui.QTreeWidgetItem, bool)

    selectionItemChanged = QtCore.pyqtSignal(bool)
    contentUpdates = QtCore.pyqtSignal()

    def __init__(self, widget=None):
        super(CustomTreeWidget, self).__init__(widget)

        self.rename_counter = False

        self.currentItemChanged.connect(self.selection_item_changed)
        self.itemChanged.connect(self.tree_item_changed)
        self.itemDoubleClicked.connect(self.tree_item_double_clicked)

    def selection_item_changed(self, current, previous):
        """Overrides widget's default signal.

        Emiited when current item selection is changed. This will also toggles
        the state of `self.add_child_btn`.
        If a child item is selected, the "Add Child" button will be disabled.

        Args:
            current (CustomTreeWidgetItem): Currently selected item.
            previous (CustomTreeWidgetItem or None): Previous selected item.
        """
        state = True
        if not current:
            # print '>>> nothing is selected'
            state = False
            return

        if current.parent():
            state = False

        self.selectionItemChanged.emit(state)

    def tree_item_changed(self, item, column):
        """Overrides widget's default signal.

        Emitted when the contents of the selected item in the column changes.

        Args:
            item (CustomTreeWidgetItem): Selected item.
            column (int): Column value of the selected item.
        """
        print '>>> selection item is changed!'
        if self.rename_counter and self.prev_name != item.text(column):
            item.setData(0, IsNewItemRole, True)
            self.rename_counter = False
            self.contentUpdates.emit()

        elif item.data(column, IsNewItemRole):
            print 'item is already an newitemrole'
            return

    def tree_item_double_clicked(self, item, column):
        """Overrides widget's default signal.

        Emitted when User performs double clicks inside the widget.

        Args:
            item (CustomTreeWidgetItem): Selected item.
            column (int): Column value of the selected item.
        """
        self.prev_name = item.text(column)
        self.rename_counter = True


class MainApp(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MainApp, self).__init__(parent)

        test_dict = {
            "menuA": ["a101", "a102"],
            "menuC": ["c101", "c102", "c103"],
            "menuB": ["b101"],
        }

        self._tree = CustomTreeWidget()
        self._tree.header().hide()
        self._tree_delegate = CustomTreeDelegate(self._tree)
        self._tree.setItemDelegate(self._tree_delegate)

        for pk, pv in sorted(test_dict.items()):
            parent = CustomTreeWidgetItem(self._tree, pk, is_tristate=True)
            for c in pv:
                child = CustomTreeWidgetItem(parent, c)

        self._tree.expandAll()

        main_layout = QtGui.QHBoxLayout()
        main_layout.addWidget(self._tree)
        self.setLayout(main_layout)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    w = MainApp()
    w.show()
    sys.exit(app.exec_())

标签: pythonpyqt4qtreewidget

解决方案


推荐阅读