在Cocoa应用程序中禁用撤消/重做

时间:2013-02-25 18:37:24

标签: cocoa undo nsundomanager

我已经实现了撤消/重做标准方式(NSUndoManager)但无法弄清楚当我的应用程序处于特定状态时如何禁用撤消/重做。

用户在我的应用中绘制内容,当他们绘制的内容上传时,我禁用了UI,当然不希望用户能够撤消/重做。

我使用的是NSView的撤销管理器,所以我猜一种方法就是让该视图辞职第一响应者。还有另一种方式吗?

5 个答案:

答案 0 :(得分:2)

如果视图是第一个响应者,您可以实施validateMenuItem:协议,根据您当前的状态禁用或启用菜单项。

 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
     SEL action = menuItem.action;

     if (action == @selector(undo:) ||
         action == @selector(redo:)) {
          return !uploadingImage;
     }
     return YES;
 }

答案 1 :(得分:1)

您可以使用

完成撤消和重做
 - (void) removeAllActions;

或使用

删除特定目标的操作
 - (void) removeAllActionsWithTarget: (id) target;

如果您只是想暂时禁用任何操作,保持撤消堆栈不变,只需使用NSMenuValidationProtocol的

禁用撤消/重做菜单项
 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem;

答案 2 :(得分:0)

我有一种类似的情况,我希望在应用程序处于特定状态时有条件地禁用某些撤消/重做操作(同时仍然允许撤消/重做其他操作)。

在视图上实现- (BOOL)validateMenuItem:(NSMenuItem *)item的方法对我不起作用(我在10.12上有一个基于文档的应用程序)。根据{{​​3}}的文档:

  

如果响应者链中有一个实现该项操作的对象,则NSMenu会检查该对象是否实现了validateMenuItem:或validateUserInterfaceItem:方法。如果没有,则启用菜单项。如果是,则菜单项的启用状态由方法的返回值确定。

视图必须添加一个撤销方法,这也是正确的。

当我探测响应者链时,我发现我的NSWindow是响应undo:的对象(虽然它不是文档界面的一部分),所以我目前的计划是使用自定义的NSWindow子类。 validateMenuItem的imeplementation,符合以下几行:

#import "Window.h"

@implementation SBXWindow

- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)screen
{
    self = [super initWithContentRect:contentRect styleMask:style backing:bufferingType defer:flag screen:screen];

    return self;
}


- (BOOL)validateMenuItem:(NSMenuItem *)item
{
    // Call super imeplementation as it appears to update the menu item title (and potentially other stuff)
    BOOL result = [super validateMenuItem:item];
    if (result == NO) {
        return NO;
    }

    if (item.action == @selector(undo:) || item.action == @selector(redo:)) {
        // Add custom logic here
    }

    return result;
}

@end

但是有警告说undo: redo:方法没有实现。这些可以通过在NSWindow上创建一个类别来消除,例如:

@interface NSWindow (SBXUndoable)

- (void)undo:(id)sender;
- (void)redo:(id)sender;

@end

不确定这样做是否有任何问题(我没有发现任何问题),但确实消除了警告。我已经把这个类改成了一个Swift类,它没有任何警告可以处理。

答案 3 :(得分:-1)

我能想到的最佳方法是在上传期间使视图的-undoManager方法返回nil,这会将其从响应程序链中删除,并导致对该视图禁用undo / redo选项。

(我还没有对此进行过测试,但是99%我确定菜单会在验证菜单选项时询问您的撤消管理器视图。)

答案 4 :(得分:-1)

文档是你的朋友。 NSUndoManager的disableUndoRegistration方法名称中包含“禁用”。由应用程序的控制器决定何时适合禁用和重新启用撤消注册。