Custom NSView avec drawRect et coordones donnes par l'utilisateur
Donio
Membre
Bonjour,
Je suis debutant ça c'est clair et j'essaye d'aprendre par la pratique. J'ai reussi a faire une sorte de calculatrice donc d'utilise les NSObject et compagnie.
Maintenant je veux dessiner un rectangle dans une custom NSView avec de dimensions donnes par l'utilisateur.
Alors je veux utiliser un NSView avec un NSObject.
Et donc ma questionest comment marier les deux. Moi j'ai reussi a faire deux controleurs un pour NSView et un pour NSObject , j'ai reussi a recupere les valeurs introduites mais je ne sais pas faire la liason avec la NSView.
J'en ai recherche sur le net et j'ai trouve que des exemples qui demontre l'utilisation de drawRect mais il le fait de maniere automatique cad au lancement de l'application le rectangle est dessiné. Moi je veux avoir la NSView dans un coin de ma fenetre et alors que les champs des dimensions ont ete remplies et le buton "dessiner" clicke que le dessin soit fait.
J'ai pense a ça, un seul controlleur DessinView.h
<br /><br />@interface DessinView : NSView {<br />}<br /><br />@interface DesenView : NSObject {<br /> IBOutlet id largeur;<br /> IBOutlet id longuer;<br />}<br /><br />-(IBAction) faitLeDessin:(id)sender;<br /><br /><br />@end<br /><br /><br /><br />@implementation DessinView<br /><br />- (id)initWithFrame:(NSRect)frame {<br /> self = [super initWithFrame:frame];<br /> if (self) {<br /> // Initialization code here.<br /> }<br /> return self;<br />}<br /><br />-(IBAction) faitLeDessin:(id)sender<br /><br />{ float l_a, l_b;<br /> <br /> l_a=[largeur floatValue];<br /> l_b=[longuer floatValue];<br /> <br /> <br />}<br /> <br />- (void)drawRect:(NSRect)rect {<br /> // Drawing code here.<br /> <br /> <br /> NSRect rect1 = NSMakeRect ( 21,21,l_a,l_b );<br /> [[NSColor blackColor] set];<br /> 1NSFrameRectWithWidth ( rect1, 1 );<br />}<br /> <br /><br />@end<br />
Mais ça ne marche pas. Donc comment je fais pour lier les deux et surtuot dessiner quand je veux pas au lancement de l'appli.
Merci.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Tout ce que je peux te dire c'est que tu es sur la bonne voie, je ne vois rien d'aberrant dans ton code et au niveau méthode c'est bien comme ça qu'il faut procéder : tu utilises des variables l_a et l_b dans ta sous-classe DessinView de NSView, que tu utilises dans le drawRect, et tu les changes avec ton IBAction quand tu cliques sur ton bouton dans ton interface, c'est bien la bonne méthode.
Par contre le problème c'est que tu as déclaré "float l_a" et "float l_b" dans ta méthode "faitLeDessin:", ce qui fait que ces variables l_a et l_b sont locale à cette méthode, et elles sont perdues dès la fin de la méthode ! Ce qu'il faut c'est déclarer "float l_a" et "float l_b" comme variables d'instance de ta classe DessinView.
Comme tu utilises l_a et l_b dans drawRect (sans les déclarer dans drawRect) et donc que tu as bien fait les choses de ce côté, je suppose que tu as déjà déclaré dans ton .h l_a et l_b comme variables d'instance de DessinView donc que tout est prêt. C'est juste que quand tu les redéclares dans "faitLeDessin:", les l_a et l_b locales masquent les l_a et l_b de ta classe...
Donc normalement il suffit d'enlever "float l_a, l_b;" dans ta méthode "faitLeDessin:" pour pas que ces variables locales masquent les variables d'instance de DessinView et que ce soit bien les l_a et l_b de DessinView qui soient modifiées !
Cocoa ça fonctionne comme ça, c'est la vue et pas des objets extérieurs qui détermine ce qui doit être dessinée ; et c'est beaucoup plus logique comme ça.
Si tu veux un rectangle qui est dessiné que quand on appuie sur un bouton, tu mets le dessin du rectangle dans un test et il faut que ce test devienne vrai que quand on a appuyé sur le bouton... Le clic sur le bouton demandant à la vue de se redessiner avec "setNeedsDisplay".
Ouf, c'est deja pas mal. Merci.
Mais mon souci c'est que si je remplace, par exemple le l_a et l_b, avec de valeurs...le dessin est fait au lancement de l'appli et n'on pas quand je click sur le bouton "dessiner".
Donc ce que tu veux dire :
au l'encement du faitLeDessin je renvoi un message a la drawRect qui dit setNeedsDisplay=yes et dans la drawRect je fait un if qui dessine le rectangle avec les variable l_a et l_b si le setNeedsDisplay est yes?
Non non ! SetNeedsDisplay:YES, c'est juste pour lui dire qu'elle devra se redessiner au prochain passage de la boucle du runtime
Il faut que tu utilises une autre variable booléenne pour savoir s'il faut dessiner le rectangle ou non... (par exemple "shouldDrawRect")
Donc tu feras d'abord "setShouldDrawRect:YES" puis "setNeedsDisplay:YES"
C'est un peu bizarre c'est comme si on parle au code.
Donc en fait le code du rectangle il est bien quelque part dans la nature et il attende qu'on lui dit : dessine le ?
Si c'est comme ça alors dans le if de initWithFrame je dois mettre setShouldDrawRect:NO ?
Ou alors j'ai pas compris la demande, mais pour moi il y a une vue DessinView qui dessine un rectangle de taille AxB, et on a dans l'interface des champs (ou des sliders enfin peu importe) pour pouvoir changer les dimensions du rectangle... Quand on modifie ces valeurs puis que l'on clique sur un bouton "Changer !", cela va mettre à jour le dessin du rectangle pour le redessiner avec les nouvelles valeurs. C'est ça ?
Dans ce cas :
- La classe DessinView (qui hérite de NSView) contient les deux dimensions largeur et hauteur du rectangle qu'elle a à dessiner
- La méthode drawRect, qui est appelée automatiquement lorsque Cocoa voit qu'il a besoin de dessiner la vue (ce n'est pas à toi d'appeler drawRect manuellement, surtout pas) ou qu'on lui a indiqué "setNeedsDisplay:YES", dans son implémentation se contente de dessiner ton rectangle en utilisant les variables d'instance largeur et hauteur de DessinView
- Il suffit de prévoir ensuite une méthode qui va mettre à jour les variables largeur et hauteur de ta DessinView, et lui envoyer dans la foulée un "setNeedsDisplay:YES"
Après pour la dernière étape, soit on met une IBAction dans DessinView qui va récupérer tout seul les valeurs dans les sliders avant de s'envoyer un setNeedsDisplay:YES, ça marche mais c'est un peu "direct", un peu trop lié à l'interface et pas très MVC, soit on met l'IBAction dans un AppController (ton NSObject, cube bleu que tu as certainement créé dans IB) et c'est cet AppController qui va récupérer les valeurs de tes sliders (ou tes champs dans lesquels tu mets tes nouvelles dimensions), et les envoyer à la méthode "setLargeur: andHauteur:" de dessinView que tu auras créé pour l'occasion (et qui va modifier la valeur de largeur et hauteur puis s'envoyer setNeedsDisplay)
En supposant que la vue joue également le rôle du contrôleur (ce qui est acceptable pour les petits trucs...)
Et il manque le setter "setShouldDrawRect" qu'on te conseillera de faire avec un @synthetize :P
Il manque également le traitement de l_a, l_b qui doivent être passés de la même manière (ex : setRectWidth:height:)
Je vois vraiment pas ce que le setShouldDrawRect vient faire là dedans, schlum ??
Justement la méthode drawRect n'est appelée que lorsque Cocoa voit qu'il est nécessaire de redessiner ton rectangle, soit parce qu'il a été masqué par une fenêtre que tu as mis au premier plan (et encore avec le backbuffering c'est pas vrai il ne redessine pas il garde en mémoire l'image dessinée) ou ce genre de cas géré automatiquement, soit parce que tu lui a explicitement dit que ton dessin n'était plus à jour et qu'il doit le redessiner (en appelant tout seul drawRect lors de la future boucle de rendu mais ça tu le laisses faire) en appelant setNeedsDisplay.
Donc tout ce mécanisme est déjà géré automatiquement, pourquoi rajouter une couche (qui en plus ne marchera pas si jamais il n'y avait pas de doublebuffering de ta vue et qu'il avait à appeler drawRect pour redessiner une partie du rectangle même s'il n'a pas changé de taille parce qu'il aurait été masqué entre temps ?)
Il veut qu'au démarrage il n'y ait aucun rectangle de dessiné... Il faut donc un "shouldDrawRect"
Ou alors on suppose que quand l_a et l_b sont tous les eux nuls, on ne dessine pas le rectangle...
Bon éventuellement dans le drawRect je pourrais faire un test si m_largeur ou m_hauteur sont nuls, ne pas dessiner, mais ça n'optimiserai que de trois fois rien puisque les méthodes NSFrameRect... doivent déjà gérer le cas où les dimensions du rectangle à dessiner son nulles.
Après j'ai pas rajouté mais il serait plus propre de déclarer une seule variable de type NSSize dans le DessinView (et de remplacer "setLargeur: andHauteur:" par "setRectSize:") mais bon c'est histoire de faire plus propre et de profiter qu'il existe une structure NSSize existante pour grouper les deux variables largeur et hauteur en une