2

我正在使用 qt 的撤消框架,它使用 qundocommand 来做一些应用程序支持撤消。有没有一种简单的方法可以用来将这些 qundocommand 保存到文件并重新加载?

4

3 回答 3

2

没有内置的方法。我认为在会话之间保存撤消堆栈并不常见。您必须自己通过迭代堆栈上的命令来序列化命令,并使用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来处理文件管理。

于 2012-05-02T22:00:23.767 回答
1

使用 Qt 的序列化,如下所述:

使用 Qt 进行序列化

然后在您的 QUndoCommands 中,您可以使用临时文件将数据写入其中:

http://qt-project.org/doc/qt-4.8/qtemporaryfile.html

但是,这可能会给您带来问题,因为每个文件都保持打开状态,因此在某些平台(Linux)上,您可能会用完打开的文件句柄。

为了解决这个问题,您必须创建一些其他工厂类型对象来处理您的命令 - 然后这可以自动传递对 QTemporaryFile 的引用。这个 factory/QUndoCommand 看护对象必须与 QUndoCommands 具有相同的生命周期。如果没有,则临时文件将从磁盘中删除,并且您的 QUndoCommands 将中断。

您可以做的另一件事是使用 QUndoCommand 作为您真正的撤消命令的代理 - 这意味着您可以节省相当多的内存,因为当您的撤消命令保存到文件时,您可以删除内部指针/将其设置为空。然后稍后恢复它。

于 2013-02-12T13:34:26.217 回答
1

这是用于序列化/酸洗 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
于 2020-02-02T13:38:51.150 回答