2010-02-03 18 views
11

Qualcuno potrebbe suggerire un metodo per selezionare tutto il testo di un NSTextField quando l'utente fa clic su di esso?selectText of NSTextField on focus

Ho trovato suggerimenti per sottoclasse NSTextField e quindi uso mouseDown o firstResponder, `ma è al di là delle mie capacità per ora. Quindi speravo che ci sarebbe stata una soluzione più semplice o qualcuno sarebbe stato così gentile da dettagliare i passaggi richiesti.

risposta

23

Non c'è una soluzione più semplice, è necessario sottoclasse NSTextField per fare ciò che si desidera. Avrai bisogno di imparare come gestire la sottoclasse se devi fare qualcosa di utile in Cocoa.

I campi di testo possono essere relativamente complessi rispetto alla sottoclasse poiché un NSTextField utilizza un oggetto NSTextView separato denominato Field Editor per gestire la modifica effettiva. Questa visualizzazione di testo viene restituita dall'oggetto NSWindow per NSTextField e viene riutilizzata per tutti i campi di testo della pagina.

Come ogni NSResponder sottoclasse, NSTextField risponde ai metodi -acceptsFirstResponder e -becomeFirstResponder. Questi vengono chiamati quando la finestra vuole focalizzare un particolare controllo o vista. Se restituisci YES da entrambi questi metodi, il tuo controllo/visualizzazione avrà lo stato di primo risponditore, il che significa che è il controllo attivo. Tuttavia, come detto, un NSTextField dà effettivamente il primo stato del risponditore editor di campo quando cliccato, quindi è necessario fare qualcosa di simile nella vostra NSTextField sottoclasse:

@implementation MCTextField 
- (BOOL)becomeFirstResponder 
{ 
    BOOL result = [super becomeFirstResponder]; 
    if(result) 
     [self performSelector:@selector(selectText:) withObject:self afterDelay:0]; 
    return result; 
} 
@end 

Questa prima chiama attuazione -becomeFirstResponder della superclasse che farà il duro lavoro di gestione dell'editor di campo. Quindi chiama -selectText: che seleziona tutto il testo nel campo, ma lo fa dopo un ritardo di 0 secondi, che ritarderà fino alla successiva esecuzione attraverso il ciclo degli eventi. Ciò significa che la selezione avverrà dopo che l'editor di campi è stato completamente configurato.

+0

Grazie mille, ha funzionato in modo bello e mi ha fatto imparare un paio di cose. Ho creato il file .m dal codice che hai fornito, il file .h in questo modo: #import @interface MCTextField: NSTextField {} @end E in Interface Builder, ho andato a File -> Leggi il file di classe, selezionato il MCTextField.h, quindi ho cambiato la classe del mio campo di testo per essere MCTextField. –

+0

Questa è anche la soluzione per un sacco di "selezionare il testo in modo programmatico" generale - le routine di selezione del testo in NSTextView, per esempio, non sparano correttamente se invocate direttamente in molte occasioni, è necessario metterle in un performSelector : afterDelay: 0 chiamata. Sigh – Adam

+1

Questo non sembra funzionare bene in 10.9 SDK. Quando faccio clic sul campo, ottengo un segno di omissione lampeggiante a meno che non inserisca un ritardo molto lungo, ad esempio 1 secondo. –

2

Alcune Offerte Swift:

import Cocoa 

class TextFieldSubclass: NSTextField { 
    override func mouseDown(theEvent: NSEvent) { 
     super.mouseDown(theEvent) 
     if let textEditor = currentEditor() { 
      textEditor.selectAll(self) 
     } 
    } 
} 

O per la selezione precisa:

import Cocoa 

class TextFieldSubclass: NSTextField { 
    override func mouseDown(theEvent: NSEvent) { 
     super.mouseDown(theEvent) 
     if let textEditor = currentEditor() { 
      textEditor.selectedRange = NSMakeRange(location, length) 
     } 
    } 
} 

versione Swift, funziona per me:

import Cocoa 

class TextFieldSubclass: NSTextField { 
    override func becomeFirstResponder() -> Bool { 
     let source = CGEventSourceCreate(CGEventSourceStateID.HIDSystemState) 
     let tapLocation = CGEventTapLocation.CGHIDEventTap 
     let cmdA = CGEventCreateKeyboardEvent(source, 0x00, true) 
     CGEventSetFlags(cmdA, CGEventFlags.MaskCommand) 
     CGEventPost(tapLocation, cmdA) 
     return true 
    } 
} 
4

La risposta da @ Rob presumibilmente ha lavorato a un certo punto, ma come @Daniel no Ted, non funziona più. Sembra che Cocoa voglia tenere traccia del mouse e trascinare una selezione in risposta a un clic, e provare a selezionare il testo in risposta a becomeFirstResponder non funziona bene con quello.

L'evento del mouse deve essere intercettato, quindi, per impedire tale tracciamento. Più o meno per tentativi ed errori, ho trovato una soluzione che sembra funzionare su OS X 10.10:

@interface MyAutoselectTextField : NSTextField 
@end 

@implementation MyAutoselectTextField 
- (void)mouseDown:(NSEvent *)theEvent 
{ 
    [[self currentEditor] selectAll:nil]; 
} 
@end 

Per quanto posso dire, per il momento in mouseDown: viene chiamato l'editor campo è già stata impostata in alto, probabilmente come effetto collaterale di becomeFirstResponder. Chiamando selectAll: seleziona quindi il contenuto dell'editor di campo. Chiamare selectText: su self invece non funziona bene, presumibilmente perché l'editor di campi è impostato.Si noti che l'override di mouseDown: qui è non chiamata super; super eseguirebbe un ciclo di tracciamento che trascinerebbe fuori una selezione e non vogliamo quel comportamento. Si noti che questa sovrascrittura di mouseDown: non influisce sulla selezione una volta che il campo di testo è diventato il primo risponditore, poiché a quel punto è chiamato l'editor di campo mouseDown:.

Non ho idea di quale gamma di versioni OS X funzioni; se ti interessa, dovrai testarlo. Sfortunatamente, lavorare con NSTextField è sempre un po 'fragile perché il modo in cui funzionano gli editor di campi è così strano e così dipendente dai dettagli di implementazione in super.

1

Mi piace la soluzione di Konstantin, ma quella verrà selezionata su ogni mouse. Qui è una variante che sto usando per selezionare in mouseDown metodo, ma solo se è diventato solo il primo risponditore:

class SelectingTextField: NSTextField { 

    var wantsSelectAll = false 

    override func becomeFirstResponder() -> Bool { 
     wantsSelectAll = true 

     return super.becomeFirstResponder() 
    } 

    override func mouseDown(with event: NSEvent) { 
     super.mouseDown(with: event) 

     if wantsSelectAll { 
      selectText(self) 
      wantsSelectAll = false 
     } 
    } 
}