Un bug d'accessoryview ou de focus ? Ou pas ?
Chacha
Membre
Salut,
Je crois avoir trouvé un bug dans Cocoa, mais je ne suis pas sûr. J'aurais besoin d'un petit coup de pouce, à la fois pour confirmer le bug (si ce n'est pas moi le fautif), et aussi pour trouver une façon de le contourner.
Voici une introduction:
-les NSSavePanel sont bien pratiques, et ils ont le bon goût d'être configurables, grâce à l'introduction d'une vue personnalisée sous forme d'"accessoryView", qui se glisse au bas du NSSavePanel. On peut ainsi rajouter des contrôles personnalisés.
-il y a une petite subtilité sur le retain/release (expliquée dans la doc), mais rien de compliqué.
-j'ai une application document-based. Le MyDocument.nib contient une accessoryView "préinstanciée", de telle sorte que chaque document dispose en permanence d'une accessoryView, sans avoir à la créer à chaque apparition du NSSavePanel. L'idée, c'est que les contrôles présents dans l'accessoryView conservent ainsi leur valeur entre deux apparitions du NSSavePanel.
-dans mon accessoryView, j'ai juste mis un textField
Voici le bug :
-Si je fais apparaà®tre ce fameux NSSavePanel plusieurs fois de suite, le nstextfield contient bien la même valeur, mais cette dernière n'apparaà®t que si le textfield a le focus ! Très étrange...
Bon, vous êtes bien avancés avec ça. Mais heureusement, j'ai fait un mini-projet XCode qui illustre ce comportement.
Des idées ?
+
Chacha
[Fichier joint supprimé par l'administrateur]
Je crois avoir trouvé un bug dans Cocoa, mais je ne suis pas sûr. J'aurais besoin d'un petit coup de pouce, à la fois pour confirmer le bug (si ce n'est pas moi le fautif), et aussi pour trouver une façon de le contourner.
Voici une introduction:
-les NSSavePanel sont bien pratiques, et ils ont le bon goût d'être configurables, grâce à l'introduction d'une vue personnalisée sous forme d'"accessoryView", qui se glisse au bas du NSSavePanel. On peut ainsi rajouter des contrôles personnalisés.
-il y a une petite subtilité sur le retain/release (expliquée dans la doc), mais rien de compliqué.
-j'ai une application document-based. Le MyDocument.nib contient une accessoryView "préinstanciée", de telle sorte que chaque document dispose en permanence d'une accessoryView, sans avoir à la créer à chaque apparition du NSSavePanel. L'idée, c'est que les contrôles présents dans l'accessoryView conservent ainsi leur valeur entre deux apparitions du NSSavePanel.
-dans mon accessoryView, j'ai juste mis un textField
Voici le bug :
-Si je fais apparaà®tre ce fameux NSSavePanel plusieurs fois de suite, le nstextfield contient bien la même valeur, mais cette dernière n'apparaà®t que si le textfield a le focus ! Très étrange...
Bon, vous êtes bien avancés avec ça. Mais heureusement, j'ai fait un mini-projet XCode qui illustre ce comportement.
Des idées ?
+
Chacha
[Fichier joint supprimé par l'administrateur]
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
.
Il faut savoir qu'un NSTextField est quelque chose d'assez complexe.
Basiquement, NSTextField affiche le contenu de son NSTextFieldCell associé.
Sauf que, lorsque on édite NSTextField, le mécanisme d'affichage de l'édition est alors pris en charge par l'éditeur NSText de la fenêtre.
Une fois l'édition terminée, NSText met à jour (ou non) NSTextFieldCell, puis raffraichit NSTextField pour mettre à jour l'affichage.
C'est cette dernière étape qui bug dans ton cas (pour une raison que je ne m'explique pas).
Pour preuve, relie le NSTextField incriminé à un outlet et un target/action.
Moi j'ai nommé l'outlet txt et l'action action.
Ensuite, implémente dans MyDocument.m les méthodes suivantes :
Que se passe t'il ?
0.1 seconde après avoir quitté le NSTextField (donc déclenchement de la méthode action), celui se raffraichit (dans la méthode du timer), et le texte réapparait.
A partir de ça, je pense qu'une parade élégante peut être trouvée !
.
J'ai effectivement pu m'en sortir grâce à ton idée.
J'ai mis 0 au timer, puisqu'apparemment il ne sera évalué qu'au prochain passage dans la RunLoop, donc après le beginSheet.
Je vais quand même soumettre ça comme un bug à Apple.
+
Chacha
[edit]
Ah, non, ça ne résout pas le bug quand le textfield perd le focus. Bah, j'ai juste à rajouter ton code et c'est bon, je pense.
[/edit]
[edit2]
Voilà , c'est bon, j'ai rajouté le même timer associé à un NSControlTextDidChangeNotification
[/edit2]
Comment faire dans ce cas?
Comme cela ça marche (le savepanel reste le même entre deux appels)
@interface MyDocument : NSDocument
{
 IBOutlet NSView* accessoryView;
 NSSavePanel * savePanel;
}
-(IBAction) openSheet:(id)sender
{
 if(!savePanel) {
savePanel = [[NSSavePanel savePanel] retain];
[savePanel setAccessoryView:accessoryView];
}
 [savePanel beginSheetForDirectory:nil file:nil modalForWindow:[self windowForSheet] modalDelegate:self
           didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
}
ah oui ça marche merci
Ici, la cause du problème serait que cet editor disparaà®t avec le panel sans rafraà®chir le text view.
Pour utiliser un timer avec un panel, il faut l'installer en mode panel
Néammoins, pour le problème posé par Chacha, il me semble que si on veut faire propre, on crée une variable pour la mise à jour ad-hoc de l'accessoryView afin qu'elle présente l'aspect voulu au moment voulu.
J'ai pas compris ta deuxième solution?
Maintenant j'ai un autre problème: j'ai deux accessory view différentes.
Et un retain du save panel fait que seulement la première vue est affichée.
Si j'essaie avec les timer, j'ai un effet de clignotement dès que le textfield perd le focus, même en réglant le timer à 0.
Ya peut-être une soluce simple:
En fait, je suis sûr que c'est à cause du textfield qui est first responder à la fermeture de la fenêtre et comme accessoryView est rajoutée à chaque fois, ça fout le bazar !
Je navigue un peu à l'aveugle là par rapport à ton problème, mais il me semble que tout serait plus simple à régler si le contenu de l'accessoryView était défini par le programme à partir d'une ou plusieurs variables de MyDocument.
En clair ne pas se contenter de [ savePanel setAccessoryView:accessoryView]
Mais y rajouter, tant à l'apparition du panel qu'au retour dans une delegate method (par exemple celle indiquée par mpergand), des mises à jours du style
à l'aller
[theTextFieldInTheAccessoryView setStringValue: textFieldValue];
au retour :
textFieldValue=[[theTextFieldInTheAccessoryView stringValue] copy];
Dès lors le panel ne sert que de view, le model étant bien à l'abri derrière le controller, instance de MyDocument.
Rien n'empêche non plus de faire après avoir récupéré les infos, un release ou un autorelease sur le savepanel dans la delegate method appelée en didEndSelector:
didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:)