2009-02-09 20 views
5

Sto tentando di utilizzare un campo NSText per l'input dell'utente intero. Il campo di testo è associato a una proprietà NSNumber e nel metodo setter pulisco il valore di input (assicurati che sia un int) e imposta la proprietà se necessario. Invio sendChangeValueForKey: e fattoChangeValueForKey :, ma l'interfaccia utente non si aggiorna ai nuovi valori mentre quel campo di testo è ancora attivo.associazione NSTextField a NSNumber

Quindi, ad esempio, è possibile digitare "12abc" nel campo di testo che il metodo setter pulisce fino a "12", ma il campo di testo mostra ancora "12abc".

Ho "Aggiornamento continuo valore" selezionato nel builder dell'interfaccia.

(Ho anche notato che il metodo setter riceve un NSString, non un NSNumber. E 'normale?)

Qual è il modo corretto di collegare un NSTextField a un NSNumber? Come si presenta il metodo setter per la proprietà? Come impedire che i valori non numerici vengano visualizzati nel campo di testo?

risposta

0

Penso che sia necessario impostare un formattatore di numeri per il tuo NSTextField.

Leggi i formattori sul sito Web di Apple: Applying Formatters.

+0

ho aggiunto un numero formattatore facendola cadere sul campo di testo come suggerito nel documento che ha sottolineato, ma non succede nulla. Posso ancora digitare caratteri non numerici. Devo fare qualcosa di diverso dal collegamento del formattatore al campo di testo? – lajos

1

Come menzionato da Ben, un modo per farlo è quello di collegare un NSNumberFormatter al campo di testo, che è piuttosto semplice da configurare nel builder dell'interfaccia e sarà probabilmente Just Work ™.

Se non vi piacciono le finestre di dialogo modali NSNumberFormatter si rivolge agli utenti quando immettono valori non numerici, è possibile creare una sottoclasse di NSNumberFormatter per implementare un comportamento di formattazione diverso, più tollerante. Penso che sia prioritario - numberFromString: rimuovere i caratteri non numerici prima di chiamare l'implementazione di super dovrebbe fare il trucco.

Un altro approccio consiste nel creare e registrare la propria sottoclasse NSValueTransformer per analizzare le stringhe in NSNumbers e viceversa, ma proverei prima a utilizzare NSNumberFormatter poiché è chiaramente la classe che è stata progettata per questo scopo esatto.

More about value transformers

10

I send the willChangeValueForKey: and didChangeValueForKey:, but the UI doesn't update to the new values while that text field is still active.

ci sono pochissime ragioni per inviare quei messaggi. Di solito, puoi fare lo stesso lavoro in modo migliore e più pulito implementando e usando gli accessor (o, meglio ancora, le proprietà). KVO ti invierà le notifiche quando lo farai.

Nel tuo caso, vuoi rifiutare o filtrare gli input fasulli (come "12abc"). Lo strumento corretto per questa attività è la convalida del valore-chiave.

Per abilitare questo, selezionare la casella "Convalida immediatamente" sull'associazione in IB e implementare un metodo di convalida.

Filtering:

- (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError { 
    NSString *salvagedNumericPart; 
    //Determine whether you can salvage a numeric part from the string; in your example, that would be “12”, chopping off the “abc”. 
    *newValue = salvagedNumericPart; //@"12" 
    return (salvagedNumericPart != nil); 
} 

Rifiutare:

- (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError { 
    BOOL isEntirelyNumeric; 
    //Determine whether the whole string (perhaps after stripping whitespace) is a number. If not, reject it outright. 
    if (isEntirelyNumeric) { 
     //The input was @"12", or it was @" 12 " or something and you stripped the whitespace from it, so *newValue is @"12". 
     return YES; 
    } else { 
     if (outError) { 
      *outError = [NSError errorWithDomain:NSCocoaErrorDomain code: NSKeyValueValidationError userInfo:nil]; 
     } 
     //Note: No need to set *newValue here. 
     return NO; 
    } 
} 

(I've also noticed that the setter method receives an NSString, not an NSNumber. Is that normal?)

Sì, a meno di utilizzare un trasformatore valore che trasforma le stringhe in numeri, collegare un numero formattatore alla presa formatter, o sostituto un NSNumber per NSString nel metodo di convalida.

+0

I metodi di validazione sembrano avere una firma di: - (BOOL) validateNewValue: (id *) errore ioValue: (NSError **) outError; Ma anche se implemento un metodo con la firma corretta e restituisco NO o correggo il valore, il campo di testo mostra ancora caratteri non numerici. – lajos

+0

Grazie per la nota sulla firma del metodo: ho corretto la mia risposta. Hai selezionato la casella "Convalida immediatamente"? Non sono sicuro di quale altro potrebbe essere il problema, senza vedere il codice. –

+0

Qui ho inviato un progetto di test: www.codza.com/files/numericFieldTest.zip Il metodo di convalida restituisce correttamente SÌ o NO (vedere i registri), ma il campo di testo mostra ancora caratteri alfa. Grazie mille per aver guardato questo. Puoi contattarmi su www.codza.com/contact e controllerò anche i commenti qui. – lajos

2

C'è un commento importante sull'eccellente risposta di Peter Hosey che mi piacerebbe portare al livello più alto (perché mi mancava al mio primo passaggio).

Se si desidera convalidare/modificare NSTextField ogni volta che si immette un carattere, anziché solo quando l'utente invia il campo, non è possibile ottenere ciò che si desidera dai soli binding. È necessario assegnare un delegato al campo di testo e quindi implementare - (void)controlTextDidChange:(NSNotification *)aNotification nel delegato. Questo verrà chiamato ogni volta che il testo cambia. Se lo desideri, puoi chiamare il validatore di valori in controlTextDidChange.

Ad esempio:

- (void)controlTextDidChange:(NSNotification *)aNotification 
{ 
    NSError *outError; 
    NSControl *textField = [aNotification object]; 
    NSString *myText = [textField stringValue]; 

    // myObject is the model object that owns the text in question 
    // the validator can modify myText by reference 
    [myObject validateValue:&myText error:&outError]]; 

    // update the NSNextField with the validated text 
    [postingObject setStringValue:myText]; 
}