python - 更新 QDockWidget 的子小部件,这在鼠标悬停时已经自然发生

标签 python pyqt pyqt5 qdockwidget

我在 QMainWindow 中有一个 QDockWidget,QDockWidget 包含一堆 QUndoView,其中包含我想要更改 QUndoView 中文本的命令。您可以通过执行 command.setText() 来完成此操作。但是,当我将鼠标悬停在 QUndoView 上时,它仅显示更新的文本。 setText 工作后甚至不会立即调用以下内容:

    self.editor().undoView().setFocus()
    self.editor().undoView().update()
    self.editor().undoView().hide()
    self.editor().undoView().show()

这是演示该问题的最少代码:

from PyQt5.QtWidgets import (QMainWindow, QDockWidget, QPushButton, QLabel, \
                             QStackedWidget, QUndoStack, QUndoCommand, QApplication, \
                             QUndoView)
import sys
from PyQt5.QtCore import QObject, pyqtSignal, Qt

class Command(QUndoCommand):
    def __init__(self):
        super().__init__()

    def undo(self):
        print("Command Undone")

    def redo(self):
        print("Command Redone")


class CommandTimeline(QDockWidget):
    def __init__(self):
        super().__init__()
        self.stackedWidget = QStackedWidget()
        self.setWidget(self.stackedWidget)

    def addUndoView(self, stack):
        view = QUndoView(stack)
        self.stackedWidget.addWidget(view)
        return view


class Obj(QObject):
    nameChanged = pyqtSignal(str)

    def __init__(self, name):
        super().__init__()
        self._name = name

    def setName(self, name):
        self._name = name
        self.nameChanged.emit(name)

    def __str__(self):
        return self._name


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.undoStack = QUndoStack()
        self.commandTimeline = CommandTimeline()
        self.commandTimeline.addUndoView(self.undoStack)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.commandTimeline)
        button = QPushButton("Click")
        self.setCentralWidget(button)
        button.clicked.connect(self.changeObjName)
        self.obj = Obj("A")
        self.addCommand()

    def addCommand(self):
        def getText(obj):
            return "The command text: " + str(obj)
        command = Command()
        command.setText(getText(self.obj))
        self.obj.nameChanged.connect(lambda name: command.setText(getText(self.obj)))
        self.undoStack.push(command)

    def changeObjName(self):
        self.obj.setName("B")


if __name__ == "__main__":
    app = QApplication([])

    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

运行此代码,请注意单击按钮后,撤消 View 中的文本不会更改,但将鼠标悬停在停靠小部件上后,文本会立即更新。

如何在 command.setText() 上触发更新?

最佳答案

QUndoCommand 不会通知文本是否更改,它被设计为具有静态文本。因此,我们必须完成该任务,在本例中使用 setFocus(),您表示它不起作用,但对我来说它起作用,因此您可能没有正确实现它,或者您的 MCVE 不可验证。

import sys

from functools import partial

from PyQt5.QtWidgets import (QMainWindow, QDockWidget, QPushButton, QLabel, \
                             QStackedWidget, QUndoStack, QUndoCommand, QApplication, \
                             QUndoView)
from PyQt5.QtCore import QObject, pyqtSignal, Qt

class Command(QUndoCommand):
    def undo(self):
        print("Command Undone")

    def redo(self):
        print("Command Redone")


class CommandTimeline(QDockWidget):
    def __init__(self):
        super().__init__()
        self.stackedWidget = QStackedWidget()
        self.setWidget(self.stackedWidget)

    def addUndoView(self, stack):
        view = QUndoView(stack)
        self.stackedWidget.addWidget(view)
        return view


class Obj(QObject):
    nameChanged = pyqtSignal(str)

    def __init__(self, name):
        super().__init__()
        self._name = name

    def setName(self, name):
        self._name = name
        self.nameChanged.emit(name)

    def __str__(self):
        return self._name


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.undoStack = QUndoStack()
        self.commandTimeline = CommandTimeline()
        self.view = self.commandTimeline.addUndoView(self.undoStack)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.commandTimeline)
        button = QPushButton("Click")
        self.setCentralWidget(button)
        button.clicked.connect(self.changeObjName)
        self.obj = Obj("A")
        self.addCommand()


    def addCommand(self):
        command = Command()
        command.setText("The command text: {}".format(self.obj))
        self.obj.nameChanged.connect(partial(self.onNameChanged, command))
        self.undoStack.push(command)

    def changeObjName(self):
        self.obj.setName("B")

    def onNameChanged(self, command, name):
        fw = QApplication.focusWidget()
        command.setText("The command text: {}".format(name))
        self.view.setFocus()
        fw.setFocus()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

关于python - 更新 QDockWidget 的子小部件,这在鼠标悬停时已经自然发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51343544/

相关文章:

python - Fork 和 exec 未产生正确的结果

Python:创建另一个共享相同数据的 python 控制台窗口

Python多重继承中的错误 "TypeError: could not convert X to Y"

python - Emit() 向不同类发出信号不起作用

python - 安装包时无法导入名称 'html5lib' 错误

pyqt - QGIS PyQt4 缺少 QString 类

python - PyQt4 Qtreewidget - 如果选中子复选框,则获取层次结构文本

python - 从多个类组成 PyQt5 UI

python - 根据列表有条件地创建组框

c++ - c++程序如何设置python代码段可以运行的环境?