如何使 NSUndoManager 的撤消/重做操作名称正常工作?

发布于 2024-10-18 21:46:41 字数 971 浏览 2 评论 0原文

我正在学习 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"];
}

这是我所期望的:

  • 我单击“打开”按钮
  • 标签更改为“打开”
  • 在“编辑”菜单中是“撤消打开标签”项,
  • 我单击该菜单项
  • 标签更改为“关闭”
  • 在“编辑”菜单中是“重做打开标签”项

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

我误解了什么,以及如何显示这些菜单项我希望他们这样做吗?

I'm learning Cocoa, and I've gotten undo to work without much trouble. But the setActionName: method is puzzling me. Here's a simple example: a toy app whose windows contain a single text label and two buttons. Press the On button and the label reads 'On'. Press the Off button and the label changes to read 'Off'. Here are the two relevant methods (the only code I wrote for the app):

-(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"];
}

Here's what I expect:

  • I click the On button
  • The label changes to say 'On'
  • In the Edit menu is the item 'Undo Turn On Label'
  • I click that menu item
  • The label changes to say 'Off'
  • In the Edit menu is the item 'Redo Turn On Label'

In fact, all these things work as I expect apart from the last one. The item in the Edit menu reads 'Redo Turn Off Label', not 'Redo Turn On Label'. (When I click that menu item, the label does turn to On, as I'd expect, but this makes the menu item's name even more of a mystery.)

What am i misunderstanding, and how can I get these menu items to display the way I want them to?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟燃烟灭 2024-10-25 21:46:41

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

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

setActionName: 仅更改“撤消”菜单项。“重做”菜单项 actionName 是自动设置的。

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

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

Remember: when you are redoing, your code must set an actionName for the Undo menu item.

When you are undoing or redoing, the actionName in the Redo menu item is set automatically.

setActionName: changes the Undo menu item only. The Redo menu item actionName is automated.

When you initially setActionName: when ![[self undoManager] isUndoing], this actionName goes to the Undo menu item. When then you choose to Undo ([[self undoManager] isUndoing] == YES, no actionNames are set by you) the undoManager automatically sets this actionName to the Redo menu item and the previous undo actionName to the Undo menu item. When you then choose to Redo, you still have to pass an actionName to go to the Undo menu item.

In other words: you have to set actionNames only when your code is not Undoing (but you must set when initially invoked or is redoing).

有木有妳兜一样 2024-10-25 21:46:41

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

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

我将向任何能够解释为什么 NSUndoManager 需要我这样做的人提供正确的答案。

After looking at some sample code, I was able to fix this by adding a condition to the setActionName: calls in each method, like this:

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

I'll give the correct answer to whoever can explain why NSUndoManager needs me to do this.

清眉祭 2024-10-25 21:46:41

因为你的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>

Because your turnOnLabel: method can be invoked three possible ways:

1) when the control that the selected is associated with is performing its target/action sequence (i.e., the NSUndoManager isUndoing and isRedoing methods would return NO)

2) when you are performing an undo operation, and the turnOnLabel: method is actually being invoked by the NSUndoManager (i.e., isUndoing = YES and isRedoing = NO)

3) when you are performing a redo operation, and the turnOnLabel: method is actually being invoked by the NSUndoManager (i.e., isUndoing = NO and isRedoing = YES)

isUndoing  isRedoing    Action
-------------------------------------------------
   0           0        Turn On Label
   0           1        Turn On Label
   1           0        Turn Off Label
   1           1        <impossible state>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文