如何访问QUndoStack
的{{1}}?
(例如,我希望能够将自定义QTextDocument
对象添加到文档的撤消堆栈中)
答案 0 :(得分:4)
我一直在阅读文档,它似乎不是直接为Widget获取QUndoStack的方法。
可能唯一的方法是创建自己的QUndoStack对象并手动添加更改,然后重新实现do / undo槽。我想看看源代码,你可以从那里获得你需要的大部分代码来存储QTextDocument中的更改。
答案 1 :(得分:2)
没有办法:(
我使用的方法是根据需要修改QTextDocument类,然后重新编译Gui模块。
静态链接是一个很好的选择。
答案 2 :(得分:0)
正如其他人所说,确实似乎无法像 2020 年 5 月那样直接访问 Undo 堆栈。用户mrjj 在Qt 论坛上的This 2017 answer 说堆栈位于qtextdocument_p.cpp
中,并且无法通过接口访问它。
相反,每个人都建议实现自己的可撤消命令,这很容易,但我找不到如此有意义的实现。此外,内置功能在 QTextDocument docs 中有详细记录,至少对我来说,重新实现它看起来不太简单:
<块引用>可以使用 setUndoRedoEnabled() 函数控制对文档执行的操作的撤消/重做。撤消/重做系统可以通过 undo() 和 redo() 插槽由编辑器小部件控制;该文档还提供了 contentsChanged() 、 undoAvailable() 和 redoAvailable() 信号,通知连接的编辑器小部件有关撤消/重做系统的状态。以下是 QTextDocument 的撤销/重做操作:
正如我们所见,它集成了许多不同类型的复杂事件,最重要的是它具有命令压缩功能。我个人非常不喜欢重新实现它的想法。
理想情况下,我们将通过 API 访问堆栈,我们就大功告成了!希望这在某个时候得到支持(如果是这种情况,请在评论中告诉我)。 在这个答案中,我展示了一种以最少的努力集成内置 QTextDocument Undo 堆栈并保留其所有功能的方法。我尝试了很多不同的方法,我最喜欢这个。希望这会有所帮助!
此代码举例说明了 QPlainTextEdit
的用法,但您可以使用其他小部件重现它。有关解释,请参阅文档字符串:
from PySide2 import QtWidgets, QtGui, QtCore
class TextDocumentUndoWrapperCommand(QtWidgets.QUndoCommand):
"""
This command is a wrapper that simply uses the text document stack, but
allows to register the action on a different stack for integration.
"""
def __init__(self, txt_editor, parent=None):
super().__init__("Text Document Action", parent)
self.txt_editor = txt_editor
def undo(self):
self.txt_editor.document().undo()
def redo(self):
self.txt_editor.document().redo()
class TextEditor(QtWidgets.QPlainTextEdit):
"""
QTextDocument document has a really nice built-in undo stack, but
unfortunately it cannot be accessed or integrated with other undo stacks.
This class exemplifies such integration, as follows:
1. Important: we do NOT disable undo/redo functionality. We keep it on!
2. Every time that QTextDocument adds a Command to its own stack, we add
a wrapper command to our own main stack
3. Every time the user sends an undo/redo event, we intercept it and send
it through our wrapper command. This way we have effectively integrated
the built-in undo stack into our own main stack.
"""
def __init__(self, parent=None, undo_stack=None):
"""
"""
super().__init__(parent)
self.setLineWrapMode(self.WidgetWidth) # matter of taste
if undo_stack is not None:
# if we provide a stack, integrate internal stack with it
self.installEventFilter(self)
self.undo_stack = undo_stack
self.document().undoCommandAdded.connect(self.handle_undo_added)
def handle_undo_added(self, *args, **kwargs):
"""
The key information is WHEN to create an undo command. Luckily,
the QTextDocument provides us that information. That way, we can keep
both undo stacks in perfect sync.
"""
cmd = TextDocumentUndoWrapperCommand(self)
self.undo_stack.push(cmd)
def eventFilter(self, obj, evt):
"""
We didn't deactivate the undo functionality. We simply want to
re-route it through our stack, which is synched with the built-in
one.
"""
if evt.type() == QtCore.QEvent.KeyPress:
if evt.matches(QtGui.QKeySequence.Undo):
self.undo_stack.undo()
return True
if evt.matches(QtGui.QKeySequence.Redo):
self.undo_stack.redo()
return True
return super().eventFilter(obj, evt)
TextEditor
然后可以简单地用作常规小部件。如果我们不向构造函数提供堆栈,则将使用默认的内置隐藏堆栈。如果我们提供一个,包装器机制会将隐藏的堆栈集成到提供的堆栈中。
注意:我没有为“仅 QTextDocument”提供解决方案,因为我无法让 eventFilter
为它工作(我很高兴听到其他人的努力)。在任何情况下, QTextDocument 总是在任何类型的父小部件/窗口内,然后这个逻辑应该完全相同。有很多论坛要求使用此功能,我认为这是发布此答案的最佳位置(否则请告诉我)。