6

標準的な方法(NSUndoManager)でundo / redoを実装しましたが、アプリが特定の状態にあるときにundo/redoを無効にする方法がわかりません。

ユーザーは私のアプリで物を描きます。彼らが描いたものがアップロードされているとき、私はUIを無効にします。もちろん、ユーザーが元に戻したりやり直したりできないようにします。

私はNSViewのUndoManagerを使用しているので、1つの方法は、そのビューをファーストレスポンダーに辞任させることだと思います。別の方法はありますか?

4

5 に答える 5

2

ビューがファーストレスポンダーである場合は、validateMenuItem:プロトコルを実装して、現在の状態に応じてメニュー項目を無効または有効にすることができます。

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

     if (action == @selector(undo:) ||
         action == @selector(redo:)) {
          return !uploadingImage;
     }
     return YES;
 }
于 2013-02-25T20:51:02.950 に答える
1

元に戻すとやり直しを完了することができます

 - (void) removeAllActions;

または、特定のターゲットのアクションを削除します

 - (void) removeAllActionsWithTarget: (id) target;

元に戻すスタックを変更せずに一時的にアクションを無効にしたい場合は、NSMenuValidationProtocolを使用して[元に戻す/やり直し]メニュー項目を無効にします。

 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem;
于 2013-02-25T20:50:15.503 に答える
0

私が考えることができる最善のアプローチは、-undoManagerアップロード中にビューのメソッドがnilを返すようにすることです。これにより、ビューがレスポンダーチェーンから削除され、そのビューの元に/やり直しオプションが無効になります。

(私はこれをテストしていませんが、メニューオプションを検証するたびに、メニューがUNDOマネージャーのビューを要求することを99%確信しています。)

于 2013-02-25T20:36:28.733 に答える
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クラスに変更しましたが、対処する警告はありませんでした。

于 2016-12-24T17:56:09.230 に答える
-1

ドキュメントはあなたの友達です。NSUndoManagerのdisableUndoRegistrationメソッドには、名前に「disable」が含まれています。UNDO登録を無効にしてから再度有効にするのが適切な時期を決定するのは、アプリのコントローラー次第です。

于 2013-02-25T20:55:27.493 に答える