【问题标题】:How can I make NSUndoManager's undo/redo action names work properly?如何使 NSUndoManager 撤消/重做操作名称正常工作?
【发布时间】:2011-07-02 11:28:44
【问题描述】:

我正在学习 Cocoa,并且我可以轻松地撤消工作。但是 setActionName: 方法让我很困惑。这是一个简单的示例:一个玩具应用程序,其窗口包含一个文本标签和两个按钮。按下开按钮,标签上显示“开”。按下关闭按钮,标签变为“关闭”。以下是两个相关方法(我为应用编写的唯一代码):

-(IBAction) turnOnLabel:(id)sender
{
    [[self undoManager] registerUndoWithTarget:self selector:@selector(turnOffLabel:) object:self];
    [[self undoManager] setActionName:@"Turn On Label"];
    [theLabel setStringValue:@"On"];
}

-(IBAction) turnOffLabel:(id)sender
{
    [[self undoManager] registerUndoWithTarget:self selector:@selector(turnOnLabel:) object:self];
    [[self undoManager] setActionName:@"Turn Off Label"];
    [theLabel setStringValue:@"Off"];
}

这是我的期望:

  • 我点击开启按钮
  • 标签变为“开启”
  • “编辑”菜单中有“撤消打开标签”项
  • 我点击了那个菜单项
  • 标签变为“关闭”
  • “编辑”菜单中有“重做开启标签”项

事实上,除了最后一个之外,所有这些都按我的预期工作。编辑菜单中的项目显示为“重做关闭标签”,而不是“重做打开标签”。 (当我单击该菜单项时,标签确实会变为 On,正如我所料,但这使菜单项的名称更加神秘。)

我有什么误解,我怎样才能让这些菜单项以我想要的方式显示?

【问题讨论】:

    标签: cocoa undo nsundomanager


    【解决方案1】:

    记住:当您重做时,您的代码必须为 Undo 菜单项设置一个 actionName。

    当您撤消重做时,Redo 菜单项中的 actionName 会自动设置。

    setActionName:仅更改撤消菜单项。重做菜单项 actionName 是自动化的。

    当您最初setActionName:![[self undoManager] isUndoing],此actionName 转到撤消菜单项。然后,当您选择撤消([[self undoManager] isUndoing] == YES,您未设置任何操作名称)时,undoManager 自动 将此操作名称设置为重做菜单项,并将前一个撤消操作名称设置为撤消菜单项。当您然后选择重做时,您仍然需要传递一个 actionName 才能转到撤消菜单项。

    换句话说:只有当你的代码不是 Undoing 时才需要设置 actionNames(但你必须在最初调用或重做时设置)。

    【讨论】:

    • 这里只提到setActionName:的功能,而不是redoActionName:undoActionName:的功能
    【解决方案2】:

    因为您的 turnOnLabel: 方法可以通过三种可能的方式调用:

    1) 当与所选控件关联的控件正在执行其目标/动作序列时(即,NSUndoManager isUndoing isRedoing 方法将返回 NO)

    2) 当您执行撤消操作时,而 turnOnLabel: 方法实际上被 NSUndoManager 调用(即 isUndoing = YES 和 isRedoing = NO)

    3) 当您执行重做操作时,而 turnOnLabel: 方法实际上是由 NSUndoManager 调用的(即 isUndoing = NO 和 isRedoing = YES)

    isUndoing  isRedoing    Action
    -------------------------------------------------
       0           0        Turn On Label
       0           1        Turn On Label
       1           0        Turn Off Label
       1           1        <impossible state>
    

    【讨论】:

    • 克拉伦斯——感谢您的回答。我理解你的意思,但我不明白为什么它对 setActionName 有影响:无论是在撤消、重做还是首次执行时调用它。无论哪种方式,据我所知,正在向撤消/重做堆栈添加或删除一个动作,并且该动作应该具有相同的名称。
    【解决方案3】:

    在查看了一些示例代码后,我能够通过向 setActionName 添加一个条件来解决此问题:在每个方法中调用,如下所示:

    if (![[self undoManager] isUndoing])
        [[self undoManager] setActionName:@"Turn On Label"];
    

    谁能解释为什么 NSUndoManager 需要我这样做,我会给出正确的答案。

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 2013-01-17
      • 1970-01-01
      • 2018-08-23
      • 2010-12-10
      • 2011-03-18
      • 2016-08-11
      • 1970-01-01
      • 2012-06-22
      相关资源
      最近更新 更多