我创建了一个自定义的QPushButton,可以从菜单或QColorDialog中选择颜色。由于它是“主题”编辑器的一部分,我还添加了对QUndoStack的支持:每次更改自定义按钮的颜色时,它都会创建QUndoCommand的子类,并将其推送到QUndoStack。
然后我意识到(根据this),每次执行QUndoStack.push(cmd)时,该命令都会被执行(这显然会导致递归,由PyQt自动“忽略”,但仍在stdout中报告)。
当调用redo()时,我通过阻止目标小部件上的信号来解决问题,但问题仍然存在:为什么推送的命令首先要执行?
在我看来,如果我将一个命令推送到撤消堆栈,则它已经被执行。
哪种情况需要(理论上已经)执行[subclassed] QUndoCommand的“再次”执行?
这种情况是否很常见,需要这种实现作为默认行为?
以下是一个最小化且不完整的示例(但足以显示问题),它不支持撤销/重做操作的信号处理,但这不是重点(我想?)。据我所理解,当调用QUndoCommand创建的信号与创建信号本身的槽重合时,问题就出现了:
然后我意识到(根据this),每次执行QUndoStack.push(cmd)时,该命令都会被执行(这显然会导致递归,由PyQt自动“忽略”,但仍在stdout中报告)。
当调用redo()时,我通过阻止目标小部件上的信号来解决问题,但问题仍然存在:为什么推送的命令首先要执行?
在我看来,如果我将一个命令推送到撤消堆栈,则它已经被执行。
哪种情况需要(理论上已经)执行[subclassed] QUndoCommand的“再次”执行?
这种情况是否很常见,需要这种实现作为默认行为?
以下是一个最小化且不完整的示例(但足以显示问题),它不支持撤销/重做操作的信号处理,但这不是重点(我想?)。据我所理解,当调用QUndoCommand创建的信号与创建信号本身的槽重合时,问题就出现了:
#!/usr/bin/env python2
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class UndoCmd(QtWidgets.QUndoCommand):
def __init__(self, widget, newColor, oldColor):
QtWidgets.QUndoCommand.__init__(self)
self.widget = widget
self.newColor = newColor
self.oldColor = oldColor
def redo(self):
self.widget.color = self.newColor
class ColorButton(QtWidgets.QPushButton):
colorChanged = QtCore.pyqtSignal(QtGui.QColor)
def __init__(self, parent=None):
QtWidgets.QPushButton.__init__(self, 'colorButton', parent)
self.oldColor = self._color = self.palette().color(self.palette().Button)
self.clicked.connect(self.changeColor)
@QtCore.pyqtProperty(QtGui.QColor)
def color(self):
return self._color
@color.setter
def color(self, color):
self._color = color
palette = self.palette()
palette.setColor(palette.Button, color)
self.setPalette(palette)
self.colorChanged.emit(color)
def changeColor(self):
dialog = QtWidgets.QColorDialog()
if dialog.exec_():
self.color = dialog.selectedColor()
class Window(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
self.colorButton = ColorButton()
layout.addWidget(self.colorButton)
self.undoStack = QtWidgets.QUndoStack()
self.colorButton.colorChanged.connect(lambda: self.colorChanged(self.colorButton.oldColor))
def colorChanged(self, oldColor):
self.undoStack.push(UndoCmd(self.colorButton, oldColor, self.colorButton._color))
app = QtWidgets.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
push
之后执行命令的必要性。 - musicamanteundoStack->push(new MoveCommand(movedItem, oldPosition));
。因此,该命令旨在通过被推送到撤销堆栈中来执行,而不是事先执行,因此需要在推送后执行该命令。 - scopchanov