DrawRect & initWithFrame
Ceetix
Membre
Bonsoir tout le monde.
Voilà j'ai une petite question et un problème.
Je voulais savoir si quand on appelle setNeedsDisplay la méthode initWithFrame est aussi rappelée?
Pour moi non, c'est juste drawRect qui est appellée mais je ne suis pas sûr.
Enfin, j'ai deux classe, une NSView(maVue) et une NSObject test)
Dans maVue je dessine et dans test j'ai une IBAction.
Quand j'utilise mon IBAction je veux modifier une variable de maVue.
Mais rien ne se passe ... Je pense que c'est mon setNeedsDisplay qui ne marche pas mais je comprends pas pourquoi là ...
Voici mon code de ma classe test :
.h
.m
Je vois pas où est mon erreur ...
ps : j'ai bien relié maVue à ma classe test sous IB .
Merci ^^
Voilà j'ai une petite question et un problème.
Je voulais savoir si quand on appelle setNeedsDisplay la méthode initWithFrame est aussi rappelée?
Pour moi non, c'est juste drawRect qui est appellée mais je ne suis pas sûr.
Enfin, j'ai deux classe, une NSView(maVue) et une NSObject test)
Dans maVue je dessine et dans test j'ai une IBAction.
Quand j'utilise mon IBAction je veux modifier une variable de maVue.
Mais rien ne se passe ... Je pense que c'est mon setNeedsDisplay qui ne marche pas mais je comprends pas pourquoi là ...
Voici mon code de ma classe test :
.h
#import <Cocoa/Cocoa.h><br />#import "libgraph.h"<br />#import "maVue.h"<br /><br />@class maVue;<br /><br />@interface test : NSObject {<br /> IBOutlet maVue *myView;<br /><br />}<br />@property(nonatomic,retain) IBOutlet maVue *myView;<br /><br />-(IBAction)test:(id)sender;<br /><br />@end<br />
.m
#import "test.h"<br /><br />@implementation test<br />@synthesize myView;<br /><br />-(IBAction)test:(id)sender<br />{<br /> /* J'alloue une variable de type maVue */<br /> myView = [[maVue alloc]init];<br /> <br /> <br /> /* Je modifie une variable de ma classe maVue */<br /> myView.afficher = 1; <br /> <br /> /* Je rafraichi mon dessin */<br /> [myView setNeedsDisplay:YES];<br /> <br /> <br />}
Je vois pas où est mon erreur ...
ps : j'ai bien relié maVue à ma classe test sous IB .
Merci ^^
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Supprime cette ligne et ça ira mieux
Tu créés une vue qui n'est reliée à aucune vue parente, et donc qui n'est pas à l'écran (donc pas visible).
En plus tu écrases la vue créée dans IB et dont le pointeur est dans l'outlet.
Bref y'a du boulot sur la compréhension du système d'affichage sous cocoa.
MErci en tout cas NO .
Mais en plus si ce n'était pas une vue déjà créée et reliée à ton IBOutlet mais que tu voulais créer la vue par code, il faudrait :
(1) utiliser initWithFrame et non init tout court (comme tu le mets d'ailleurs dans ton titre de sujet, pourquoi tu n'as pas fait l'erreur dans ton code ? arf)
(2) ajouter la vue créer en tant que subView d'une vue parente si tu veux la voir un jour
En fait je pense que j'ai du mal à voir que quand je mets des Outlets mon programme le fait tout seul. Car on ne voit rien en code, juste des tirettes bleues à relié.... mystique pour moi ^^.
Regarde les classes NSKeyedArchiver / NSKeyedUnarchiver ; un .nib fonctionne un peu comme ça... ce sont des objets sérialisés qui sont désérialisés au moment du chargement du .nib
Ok je vais regarder ça, c'est interessant, je savais pas du tout comment ça se passait.
Merci
Ne serais-ce que le départ de l'appli. Après l'entré dans UIApplication, pfffuit je sais rien de ce qui se passe jusqu'au retour dans awakeFromNib de la vue que j'ai déclaré dans IB...Pour l'instant ça reste magique pour moi et c'est vraiment pas agréable.
1) On définit des objets dans Interface Builder, éventuellement interconnectés entre eux via les IBOutlets & co, on règle leurs propriétés via la palette d'inspecteur, on les positionne les uns par rapport aux autres (positionnement d'une UIView dans une UIView parente en tant que subview, ce qui fait à la fois la définition de sa frame et l'ajout en tant que subview)... tout ça est fait dans IB donc.
2) Ensuite, quand on appelle "[tt]initWithNibName: bundle[/tt]", cela va "désarchiver" le fichier NIB, c'est à dire qu'en interne il va décrypter (désérialiser) le fichier NIB et créer les objets qui sont sérialisés dans le NIB, les "configurer" (ajuster leurs propriétés) d'après les valeurs que tu as mis dans IB, et faire les connexions (IBOutlets) que tu as faites dans IB, pour faire pointer ces IBOutlets (qui ne sont en fait que des variables d'instance) vers les objets créés par le désarchivage. C'est pour ça que sur chaque objet créé par le "désarchivage" d'un NIB est appelée la méhode "initWithCoder" et non juste "init" ou "initWithFrame" : c'est bien une désérialisation qui est effectuée, comme quand on transforme un objet pour l'encoder dans un fichier, puis qu'on le recharge ensuite depuis le fichier plus tard.
3) Donc [tt]initWithNibName:bundle:[/tt] désarchive le NIB et va permettre de remplacer tout plein de alloc/init qu'on aurait fait par code sinon pour créer tous les objets qui sont sérialisés dans le NIB, tout plein de objet.machin = truc pour configurer les propriétés des objets ainsi créés, ou l'attribution des IBActions, ou les addSubview pour créer la hiérarchie des vues... Bref ça gagne quand même un temps fou et un sacré paquet de lignes de code.
4) Il n'y a que les objets "Proxy" de votre NIB qui ne sont pas créés lors du désarchivage dudit NIB, et ne servent que de "placeholder", pour représenter un objet existant. C'est rarement utilisé... sauf dans le cas particulier et important du "File's Owner", qui représente l'objet sur lequel on appelle initWithNibName justement, et qui a donc demandé le désarchivage du NIB.
Une fois que tous les objets ont été désarchivés du NIB, donc alloués et créés à cette occasion, la méthode "awakeFromNib" est appellée sur chacun. Donc contrairement au cas de initWithCoder appellé au moment où l'objet est créé par le désarchivage du NIB, dans le cas de awakeFromNib on est assuré que tous les autres objets du NIB sont créés donc on peut appeler des méthodes dessus, ou être sûr que les IBOutlets sont bien connectés.
Ensuite pour répondre à Greensource, la méthode UIApplicationMain (appellée dans le main de main.m) est en effet un peu magique... en fait elle fait un sacré paquet de trucs :
1) Elle va initialiser tout ce qu'il faut pour l'application, puis regarder dans le fichier Info.plist s'il y a un "Main Nib File" d'indiqué dedans, ce qui est souvent "MainWindow" par défaut. Si c'est le cas, l'application va automatiquement appeller toute seule initWithNibName:bundle: en interne pour t'éviter d'avoir à le faire, et charger ainsi automatiquement le NIB principal au lancement de ton appli. Si tu ne précises pas de "Main Nib File" dans le Info.plist, c'est à toi soit de charger l'interface, soit tout par code, soit avec un NIB en appelant initWithNibName sur un objet à toi...
2) Elle crée ensuite une boucle (runLoop) qui va boucler jusqu'à ce qu'on demande à l'application de quitter.
3) Dans cette boucle, elle gère les événements : elle dépile les événements genre touchers écran, notifications, etc... de la pile et les traite puis elle appelle les bonnes méthodes en conséquence.
Je me pose une question à propos de ce que tu dis. On dirais qu'on peut soit créer une vue avec IB soit par code. Mais moi j'aimerais pouvoir faire juste le minimum avec IB:
Créer une view mère qui contient ma vue Plateau et en dessous une vue barre d'état. Le tout assez vierge et ensuite via mon code, dessiner les cases sur la vue board et des boutons sur la vue barre d'état. J'ai vaguement cru comprendre qu'il fallait utiliser loadView du controllerView.
Tous les suffrages disent que tu es plus clair que moi
Pourtant c'est pas faute d'avoir essayé et dans plusieurs sujets :P
Enfin... je pense qu'il y a des lectures de " Cocoa par la Pratique " qui se perdent
J'ai pas trouver de bon exemple en tout cas pour l'instant.
Oui je suis d'accord avec Greensource.
En effet pour créer la vue entièrement par code et non par IB, il faut mettre le code dans loadView.
Par contre si vous voulez compléter une interface chargée par IB, et pas complètement tout créer "from scratch", il faut "attendre" que les éléments créés par le NIB soient prêts ! Par exemple si dans votre XIB vous avez placé une vue et un bouton dedans, juste ça, et que vous voulez compléter par code en rajoutant 3 sous-vues à votre vue... Ben il va falloir faire des "addSubview" sur la vue en question... donc encore faut-il que cette dernière ait été créée précédemment. Car si vous essayez de le faire avant que la vue ne soit créée par IB, vous n'allez pas aller loin
loadView est appellé sur le ViewController lorsque ce dernier a besoin de charger sa vue, c'est donc ici qu'il faut mettre le code si on crée l'interface entièrement par code. Par contre c'est viewDidLoad qui est appelé juste après que le ViewController a chargé sa vue, celle qu'il a créé en désarchivant le NIB par exemple. Donc c'est là qu'il faut mettre le code pour rajouter des éléments d'interface au bout de vue créé par le NIB.
Si vous vouliez rajouter 3 vues de taille 100x100 chacune dans la vue principale du ViewController, l'une en 0,0 l'autre en 0,120 et la 3e en 0,240 par exemple, la 2e étant une ImageView avec l'image "Toto.png" (présente dans les resources de votre projet) :
- dans IB c'est pas méchant, il suffit de faire glisser/déposer 2 UIViews et une UIImageView de la palette "Library" vers la vue de votr ViewController, les positionner, et choisir "Toto" dans le menu déroulant des images pour l'ImageView.
- Par code ça donnerait : Et encore là je n'ai pas réglé bcp de propriétés. Si dans IB vous avez des cases cochées/décochées dans la palette d'inspecteur (genre userInteractionEnabled) ou des menus déroulants que vous modifiez (genre le mode de votre UIView de ScaleToFit à ScaleToFill ou autre) il faut bien sûr effectuer ces réglages par code à la place dans la solution en code.
C'est une pédagogie différente :P
Moi j'aime pas leur mâcher le boulot, donc je donne des pistes d'investigation pour les forcer à aller plus loin !
Ah là là , qu'est-ce qu'ils sont flemmards les jeunes de nos jours
Par contre si vraiment je galère et comprends pas en savoir un peu plus n'est pas de refus
Moi aussi je suis pas fan de mâcher le travail, sinon ça leur apprend pas à chercher par eux-mêmes...
Seulement parfois un exemple vaut mieux qu'un long discours
Bon ok là j'ai donné du code, mais c'était du code d'exemple justement, et pas le code tout fait dont ils avaient forcément besoin, y'a encore un sacré paquet à adapter
Par exemple je n'ai pas parlé des contraintes de redimentionnement des vues quand on les places dans une subView, ces contraintes que l'on fixe dans l'onglet avec l'icône de la petite réglette dans la palette d'Inspecteur dans IB, pour dire quelles dimensions doivent être fixes et lesquelles sont flexibles quand la vue se redimentionne... Ca aussi faut le spécifier par code quand on crée l'interface par code... Et c'est pour toutes ces choses là que IB reste quand même un outil bien pratique (mais on faut savoir faire les 2 car parfois passer par le code même pour la création d'interface ça peut être utile)