我正在使用 qt 的撤消框架,它使用 qundocommand 来做一些应用程序支持撤消。有没有一种简单的方法可以用来将这些 qundocommand 保存到文件并重新加载?
3 回答
没有内置的方法。我认为在会话之间保存撤消堆栈并不常见。您必须自己通过迭代堆栈上的命令来序列化命令,并使用QDataStream保存每个命令的唯一数据。它可能看起来像这样:
...
dataStream << undoStack->count(); // store number of commands
for (int i = 0; i < undoStack->count(); i++)
{
// store each command's unique information
dataStream << undoStack->command(i)->someMemberVariable;
}
...
然后您将再次使用 QDataStream 将数据反序列化回 QUndoCommands。
您可以使用QFile来处理文件管理。
使用 Qt 的序列化,如下所述:
然后在您的 QUndoCommands 中,您可以使用临时文件将数据写入其中:
http://qt-project.org/doc/qt-4.8/qtemporaryfile.html
但是,这可能会给您带来问题,因为每个文件都保持打开状态,因此在某些平台(Linux)上,您可能会用完打开的文件句柄。
为了解决这个问题,您必须创建一些其他工厂类型对象来处理您的命令 - 然后这可以自动传递对 QTemporaryFile 的引用。这个 factory/QUndoCommand 看护对象必须与 QUndoCommands 具有相同的生命周期。如果没有,则临时文件将从磁盘中删除,并且您的 QUndoCommands 将中断。
您可以做的另一件事是使用 QUndoCommand 作为您真正的撤消命令的代理 - 这意味着您可以节省相当多的内存,因为当您的撤消命令保存到文件时,您可以删除内部指针/将其设置为空。然后稍后恢复它。
这是用于序列化/酸洗 QUndoCommands 的 PyQt 解决方案。棘手的部分是让父母先打电话__init__
,然后是孩子。此方法依赖于__setstate__
在父级之前调用所有子级,这发生在酸洗时,因为子级在父级中返回__getstate__
。
class UndoCommand(QUndoCommand):
"""
For pickling
"""
def __init__(self, text, parent=None):
QUndoCommand.__init__(self, text, parent)
self.__parent = parent
self.__initialized = True
# defined and initialized in __setstate__
# self.__child_states = {}
def __getstate__(self):
return {
**{k: v for k, v in self.__dict__.items()},
'_UndoCommand__initialized': False,
'_UndoCommand__text': self.text(),
'_UndoCommand__children':
[self.child(i) for i in range(self.childCount())]
}
def __setstate__(self, state):
if hasattr(self, '_UndoCommand__initialized') and \
self.__initialized:
return
text = state['_UndoCommand__text']
parent = state['_UndoCommand__parent'] # type: UndoCommand
if parent is not None and \
(not hasattr(parent, '_UndoCommand__initialized') or
not parent.__initialized):
# will be initialized in parent's __setstate__
if not hasattr(parent, '_UndoCommand__child_states'):
setattr(parent, '_UndoCommand__child_states', {})
parent.__child_states[self] = state
return
# init must be called on unpickle-time to recreate Qt object
UndoCommand.__init__(self, text, parent)
for child in state['_UndoCommand__children']:
child.__setstate__(self.__child_states[child])
self.__dict__ = {k: v for k, v in state.items()}
@staticmethod
def from_QUndoCommand(qc: QUndoCommand, parent=None):
if type(qc) == QUndoCommand:
qc.__class__ = UndoCommand
qc.__initialized = True
qc.__parent = parent
children = [qc.child(i) for i in range(qc.childCount())]
for child in children:
UndoCommand.from_QUndoCommand(child, parent=qc)
return qc