2013-02-25 10 views
5

Ho implementato l'annullamento/ripristino del modo standard (NSUndoManager) ma non riesco a capire come disabilitare gli annullamenti/i ripristini quando la mia app si trova in uno stato specifico.Disabilita annulla/ripristina nell'app Cocoa

Gli utenti disegnano cose nella mia app e quando ciò che hanno disegnato sta caricando, disabilito l'interfaccia utente e, naturalmente, non voglio che l'utente sia in grado di annullare/ripristinare.

Io uso un gestore di annullamento di NSView, quindi immagino che un modo possa essere quello di fare in modo che quella vista si dimostri primo risponditore. C'è un altro modo?

risposta

1

È possibile finalizzare undo e redo con

- (void) removeAllActions; 

o rimuovere azioni per un target specifico con

- (void) removeAllActionsWithTarget: (id) target; 

Se si vuole semplicemente disattivare eventuali azioni per un certo tempo, lasciando invariata la stack di annullamento, è sufficiente disabilitare t egli Undo/Redo voci di menu utilizzando del NSMenuValidationProtocol

- (BOOL)validateMenuItem:(NSMenuItem *)menuItem; 
+0

Sì. Questo è stato. Dovuto implementare (IBAction) annullare: (id) mittente però. – Sebastian

-1

L'approccio migliore che riesco a pensare è che il metodo -undoManager della vista ritorna nil durante i caricamenti, che lo rimuoverà dalla catena del risponditore e che le opzioni di annullamento/ripetizione siano disabilitate per quella vista.

(non ho ancora testato questo, ma sono sicuro al 99% che i menu vi chiederà la vostra vista per il manager di annullamento ogni volta che convalida le opzioni del menu.)

2

Se la vista è il primo risponditore, è possibile implementare il protocollo validateMenuItem: per disattivare o attivare le voci di menu in base al vostro stato attuale.

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

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

La documentazione è tua amica. Il metodo disableUndoRegistration di NSUndoManager ha "disabilitato" nel suo nome. È compito dei controllori della tua app decidere quando è opportuno disabilitare e riattivare la registrazione della registrazione.

+0

Riguarda l'impostazione degli eventi di annullamento, non la disattivazione dei menu di annullamento/ripristino. – martinjbaker

0

Avevo una situazione simile in cui volevo disattivare condizionatamente alcune operazioni di annullamento/ripristino quando l'app si trova in uno stato specifico (pur consentendo di annullare/ripristinare le altre operazioni).

Il metodo di implementazione di - (BOOL)validateMenuItem:(NSMenuItem *)item su una vista non funziona per me (ho un'app basata su documenti su 10.12). Per la documentazione in https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/MenuList/Articles/EnablingMenuItems.html:

Se c'è un oggetto nella catena risponditore che implementa l'azione del prodotto, NSMenu poi controlla se l'oggetto implementa il validateMenuItem: o validateUserInterfaceItem: metodo. In caso contrario, la voce di menu è abilitata. In tal caso, lo stato abilitato della voce di menu è determinato dal valore di ritorno del metodo.

La vista dovrebbe aggiungere un metodo di annullamento che fa anche la cosa giusta.

Quando ho sondato la catena risponditore, ho scoperto che la mia NSWindow era l'oggetto che ha risposto alla undo: (anche se non è parte dell'interfaccia documentato), quindi il mio piano attuale è quello di utilizzare un NSWindow sottoclasse personalizzato con l'imeplementation di validateMenuItem , lungo le linee di:

#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 

Tuttavia ci sono avvertimenti che i undo:redo: metodi non sono implementati. Questi possono essere eliminati con la creazione di una categoria NSWindow, come ad esempio:

@interface NSWindow (SBXUndoable) 

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

@end 

Non so se ci sono dei problemi nel fare questo (non ho notato alcuna), ma lo fa eliminare gli avvertimenti. Da allora ho cambiato la classe in una classe Swift, che non aveva alcun avvertimento da affrontare.