在Cocoa应用程序中禁用撤销/重做功能

6

我已经按照标准方式(NSUndoManager)实现了撤销/重做,但是不知道如何在我的应用处于特定状态时禁用撤销/重做。

用户在我的应用中绘制内容,当他们绘制的内容正在上传时,我会禁用UI,当然也不希望用户能够执行撤销/重做。

我使用NSView的撤销管理器,所以一种方法可能是让该视图放弃第一个响应者。还有其他方法吗?

5个回答

2
如果视图是第一响应者,您可以实现validateMenuItem:协议,根据当前状态禁用或启用菜单项。
 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
     SEL action = menuItem.action;

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

1

您可以使用撤销和重做来完成操作

 - (void) removeAllActions;

或者针对特定目标删除操作

 - (void) removeAllActionsWithTarget: (id) target;

如果您只是想在一段时间内禁用任何操作,同时保持撤销堆栈不变,只需使用NSMenuValidationProtocol禁用Undo/Redo菜单项即可。
 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem;

是的,成功了。不过必须要实现 (IBAction)undo:(id)sender。 - Sebastian

0
我能想到的最好方法是在上传期间使视图的-undoManager方法返回nil,这将从响应链中删除它并导致该视图的撤消/重做选项被禁用。
(我没有测试过,但我99%确定菜单在验证菜单选项时会要求您的视图提供撤消管理器。)

0

我曾经遇到过类似的情况,当应用程序处于特定状态时,我想有条件地禁用某些撤销/重做操作(同时仍允许其他操作进行撤销/重做)。

在视图上实现- (BOOL)validateMenuItem:(NSMenuItem *)item方法对我不起作用(我在10.12上有一个基于文档的应用程序)。根据https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/MenuList/Articles/EnablingMenuItems.html中的文档:

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

视图还必须添加一个执行正确操作的撤销方法。

当我探测响应链时,我发现我的NSWindow是响应undo:的对象(尽管它不是文档界面的一部分),所以我的当前计划是使用自定义的NSWindow子类,并实现validateMenuItem,大致如下:
#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类,没有任何需要处理的警告。


-1

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


这是关于撤销事件设置的问题,而不是禁用撤销/重做菜单。 - martinjbaker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接