Une méthode qui ne veut obéir qu'à  une partie des boutons et pas aux autres!

HerveHerve Membre
janvier 2011 modifié dans API AppKit #1
Problème résolu, merci pour votre aide

Bonjour à  tous,

Quel est ce tour de magie???

J'ai deux séries de boutons créés (grâce à  l'aide de membres de ce forum d'ailleurs) par code, une méthode de calculs (dans l'App controller) dont les résultats modifient la couleur de la seconde série de boutons. Tout va bien jusque là  :
série de boutons 1 > méthode (void) de calculs > série de boutons 2. Très bien, tout va bien.

Cette méthode de calculs est appelée aussi par une autre série de boutons plus généraux que j'ai créé avec Interface Bulder>IIBOutlet dans l'App Controller;

boutons IB > méthode de calculs : très bien, les calculs sont bien réalisés.
mais méthode de calcul > série de boutons 2  : le message n'arrive pas!!!!!

Le message consiste en une série de set(float) (faits avec property/synthesize) et une méthode :

- (void) redessine{<br />	NSLog(@&quot;appel redessine palette&quot;);<br />	[self setNeedsDisplay:YES];<br />}<br />


(le texte du NSLog n'apparaà®t pas non plus dans la console.)

Est-ce le moment d'employer des "NSNotifications", des "Key observer" et autres nouveautés dans Cocoa par rapport à  Java? J'ai passé la journée à  essayer de comprendre. Les boutons de la première série agissent très bien sur la méthode pourtant!!!

Quelqu'un ici aurait une idée de ce que cette chose peut être? :)

Réponses

  • muqaddarmuqaddar Administrateur
    14:03 modifié #2
    On pourrait voir le target et l'action appelés dans le code qui génère les boutons ?
  • laudemalaudema Membre
    14:03 modifié #3
    dans 1296069248:


    - (void) redessine{<br />	NSLog(@&quot;appel redessine palette&quot;);<br />	[self setNeedsDisplay:YES];<br />}<br />
    


    (le texte du NSLog n'apparaà®t pas non plus dans la console.)

    Est-ce le moment d'employer des "NSNotifications", des "Key observer" et autres nouveautés dans Cocoa par rapport à  Java? J'ai passé la journée à  essayer de comprendre. Les boutons de la première série agissent très bien sur la méthode pourtant!!!

    Quelqu'un ici aurait une idée de ce que cette chose peut être? :)

    NSlog absent => méthode pas appelée.
    Méthode appelée par le couple Target/Action
    Vérifier que les boutons ont bien leur target fixée sur l'objet qui contient la méthode (et que l'objet n'est pas "nil" au runtime).
    Si la cible est bien là  regarder si l'Action est la bonne.

    setTarget:
    Sets the target object to receive action messages from the receiver's cell.

    <br />- (void)setTarget:(id)anObjectQuiFaitRedessine;<br />
    


    setAction:
    Sets the receiver's action method to the specified selector.

    <br />- (void)setAction:@selector(redessine:)<br />
    

    PS: quand on les crée dans IB Action a toujours un paramètre: (id)sender et donc @selector(uneMethode:) uneMethode doit avoir ses deux points : qui signalent un argument à  venir. IB t'y oblige, c'est à  ce genre de détails qu'on l'apprécie...
    Je suis un peu surpris de voir que tes autres boutons font fonctionner la méthode redessine sans argument d'ailleurs...
    J'attendrais plutôt une méthode
    <br />//Ecrit depuis Safari<br />- (IBAction)redessine: (id)sender{<br />&nbsp; &nbsp; NSLog (@&quot;sender est %@&quot;, sender);//Donnera la référence du pointeur sur sender et sa classe<br />&nbsp; &nbsp; [self setNeedsDisplay:YES];<br />}<br />
    

  • HerveHerve Membre
    14:03 modifié #4
    Merci pour vos réponse qui m'apportent des pistes de réflexion intéressantes.

    Les deux méthodes à  l'évoute des boutons ont bien un (id sender ou pour l'autre un (NSButton*) sender.
    Les boutons qui marchent ont :
    - (void) buttonClicked:(NSButton *)sender<br />{<br />	for (int i = 0; i&lt;66; i++){<br />		if (sender == (MonBouton *) boutons[i]){<br />			[self setValSat1:[boutons[i] valSat]];//récupération dans la classe AppControle de valeurs stockées avec le bouton<br />			[self setValBright1:[boutons[i] valBright]];//idem	<br />			[self calculeValeurs];//appel de la classe de calculs<br />		}<br />	}<br />}<br />
    


    Les IBAction qui ne marchent qu'à  moitié ont :
    - (IBAction) antagoniste: (id) sender{<br />	[self setValGenerale:1];//valGenerale est une autre valeur de l&#39;App Controller, là , ça marche bien.<br />	[self calculeValeurs];//la méthode est bien appelée.<br />}<br />
    


    En fin de calculeValeurs, il y a :
    for (int j = 0; j&lt;24; j++){<br />	[boutonsPalette[j] redessine];<br />	}<br />
    


    C'est cela qui ne marche qu'avec les premiers boutons.

    J'ai fait comme en Java, appelé une méthode de classe (déclarée dans son fichier d'en tête bien sûr.) Comme le bouton ne l'appelle pas directement, j'ai pensé ne pas devoir mettre de (id) sender. J'ai essayé de le mettre d'ailleurs, mais comme cette méthode est également appelée lors de l'instanciation des boutons, et ailleurs encore... cela bloque l'ouverture du programme.

    En fait, cette méthode : "calculeValeurs" est la plaque tournante du programme. Elle va être constamment employée. C'est pourquoi je pensais aux écouteurs, mais cela m'étonne quand même : mes classes sont capables de gérer deux ou trois float tout de même!! La structure du programme est tout de même simple.
  • CéroceCéroce Membre, Modérateur
    14:03 modifié #5
    Je comprends mal ce que tu essaies de faire. J'ai toutefois dans l'idée que tu n'as pas bien intégré le concept du Modèle-Vue-Contrôleur, qui sépare l'applications en 3 couches:
    - Vue: ce sont les boutons, champs de texte, etc.
    - Modèle: il s'agit du code "métier"
    - Contrôleur: le code qui fait le lien entre les deux.

    Les méthodes d'action font forcément partie du Contrôleur.

    Le stockage des données et les calculs se font forcément dans la couche Modèle. Les méthodes -calculeValeurs, -setValSat1, -setValBright1, et -setValGenerale doivent faire partie de cette couche et n'ont rien à  faire dans un contrôleur:

    @interface ColourCorrection: NSObject<br />{<br />	float brightness;<br />	float saturation;<br />	float general;	<br />}<br /><br />- (void) setBrightness:(float)newBrightness;<br />- (float) brightness;<br />etc.<br />
    


    Qui crée le modèle ?
    En général, c'est le document (sous-classe de NSDocument). Il passe ensuite le modèle aux autre contrôleurs.


    La synchronisation des vues et du modèle est du ressort du contrôleur. Lors d'un clic d'un bouton:
    1) Le contrôleur appelle la méthode du modèle qui convient
    2) Le contrôleur récupère le résultat dans le modèle et met à  jour les vues.

    Puisque le modèle est modifié à  l'initiative du contrôleur, il n'est pas nécessaire (pour l'instant) que le contrôleur observe les modifications du modèle. Quand tu auras un tel besoin, tu pourras utiliser les notifications (NSNotificationCenter) ou le Key-Value Observing.
  • HerveHerve Membre
    14:03 modifié #6
    Merci Céroce,

    La première série de boutons permet de sélectionner des valeurs HSB (on les voit tout simplement), la méthode de calculs calcule des palettes suivant différents algorithmes, la seconde série de boutons affiche ces palettes. On doit ensuite pouvoir dessiner avec à  l'écran en sélectionnant des couleurs dans la palette.

    En effet, j'ai peut-être mal compris comment concevoir l'architecture même d'un programme Cocoa. En Java, je sur-spécialisais chaque classe. Dans le bouquin de Hillegass, j'ai cru comprendre que l'on résonnait différemment en Cocoa: une classe principale très centralisatrice communique avec toutes les autres, leur distribuant et récoltant d'elles les informations dont elles ont besoin.

    Pour l'instant, mon architecture est :
    AppController (qui dérive de NSView) crée les deux tableaux de boutons, gère les outlets des boutons IB, fait les calculs.
    une classe de boutons A (celle qui sera utilisée en tableaux et qui montre des HSB)
    une classe de boutons B (utilisée elle aussi en tableau, qui montre la palette) (ces deux classes ont une méthode de dessin propre, un drawRect à  elles, indépendante de celle de l'AppController)
    il y aura une classe "figure" stockant des valeurs pour le dessin(des points pour les NSBezierPath, des couleurs), et sans doute aussi une classe faisant ce dessin (à  partir des informations données par un NSMutableArray de "figures") , liée à  une ImageView dans IB.

    Si je te comprends bien, il faudrait qu'une classe à  part gère les calculs, classe qui serait appelée par AppController. C'est bien possible.

    D'ailleurs, pour que mes tableaux de boutons s'affichent, j'ai dû appeler les méthodes les créant dans le "drawRect" de l'AppController. Bizarrement, la méthode "init" de l'AppController semble ne pas être appelée, ou plutôt les choses que j'instancie dedans semblent n'être pas enregistrées (je voulais y instancier un certain nombre de valeurs).

    Bon, je vais essayer de trouver une doc, bien que j'ai déjà  lu les documents Apple et un livre sur le sujet. C'est vrai que j'ai du mal à  bien saisir cette nouvelle architecture. Je croyais avoir compris, mais dans les faits, cela ne marche pas comme prévu...
  • AliGatorAliGator Membre, Modérateur
    14:03 modifié #7
    J'ai pas tout lu mais quand mon regard a croisé cette ligne...
    dans 1296121885:

    AppController (qui dérive de NSView) crée les deux tableaux de boutons, gère les outlets des boutons IB, fait les calculs.
    Ouch ! Ca c'est de l'anti-MVC par excellence ^^
  • HerveHerve Membre
    14:03 modifié #8
    Merci pour le tuyau. Je cherche à  MVC et je vous tiens au courant.

    (je n'étais pas certain de mon archi d'ailleurs...)
  • CéroceCéroce Membre, Modérateur
    janvier 2011 modifié #9
    dans 1296121885:

    En effet, j'ai peut-être mal compris comment concevoir l'architecture même d'un programme Cocoa. En Java, je sur-spécialisais chaque classe.

    Ce n'est pas une question de langage, c'est une question de méthodologie. Même en Java, je t'assure qu'on préfère la composition à  l'héritage. ("Extend is Evil"). Tous les bouquins sérieux sur la POO insistent sur ce point.
    Java et ObjC sont très similaires; ils sont beaucoup plus inspirés par Smalltalk que par C++.

    L'héritage crée une dépendance forte entre deux classes. La composition oblige à  définir précisément les interfaces, ce qui clarifie les dépendances d'un objet connecté à  un autre.
    Dans ces deux langages, l'héritage multiple n'existe pas (une classe ne peut hériter que d'une classe à  la fois). Par contre, on peut définir des Interfaces en Java, qu'on appelle des Protocoles en ObjC.

    dans 1296121885:

    Dans le bouquin de Hillegass, j'ai cru comprendre que l'on résonnait différemment en Cocoa: une classe principale très centralisatrice communique avec toutes les autres, leur distribuant et récoltant d'elles les informations dont elles ont besoin.

    Pas forcément dans le principe, mais c'est vrai dans les faits: un document est souvent lié à  un fichier sur le disque. Il faut une classe centralisatrice (en général NSDocument), qui lit le fichier et construit la hiérarchie des objets grâce à  son contenu.

    dans 1296121885:

    AppController (qui dérive de NSView) crée les deux tableaux de boutons, gère les outlets des boutons IB, fait les calculs.

    Comme souligné par Ali, il y a un gros problème de conception: une vue (héritière de NSView) est un objet qui s'affiche à  l'écran et réagit aux événements (clics, frappe...). Gérer des vues est le travail d'un contrôleur.

    Un Contrôleur hérite directement de NSObject. Il existe les classes NSViewController et NSWindowController qui permettent de charger respectivement une vue et une fenêtre depuis un fichier .nib, mais le principe reste le même.

    dans 1296121885:

    une classe de boutons A (celle qui sera utilisée en tableaux et qui montre des HSB)
    une classe de boutons B (utilisée elle aussi en tableau, qui montre la palette) (ces deux classes ont une méthode de dessin propre, un drawRect à  elles, indépendante de celle de l'AppController)

    Les boutons doivent être créés et gérés par un Contrôleur.
    J'ai quand même l'impression que tu te prends la tête pour rien. Est-ce que les boutons NSColorWell ne pourraient pas convenir ?

    dans 1296121885:

    il y aura une classe "figure" stockant des valeurs pour le dessin(des points pour les NSBezierPath, des couleurs),

    La classe Figure fait partie de la couche Modèle.

    dans 1296121885:

    et sans doute aussi une classe faisant ce dessin (à  partir des informations données par un NSMutableArray de "figures") , liée à  une ImageView dans IB.

    Ce schéma fonctionne, mais il implique de créer une NSImage et de dessiner dedans, puis de l'affecter à  la NSImageView.
    Tu verras qu'il est plus simple de créer une Vue (qui hérite donc de NSView) à  laquelle le contrôleur passera une liste de Figures à  dessiner dans sa méthode -[drawRect:].

    dans 1296121885:

    D'ailleurs, pour que mes tableaux de boutons s'affichent, j'ai dû appeler les méthodes les créant dans le "drawRect" de l'AppController. Bizarrement, la méthode "init" de l'AppController semble ne pas être appelée, ou plutôt les choses que j'instancie dedans semblent n'être pas enregistrées (je voulais y instancier un certain nombre de valeurs).

    L'initialiseur désigné pour NSView est -[initWithFrame:], pas -[init].
    Cette locution bizarre est utilisée dans la doc pour préciser quelle méthode d'initialisation doit être appelée.
  • HerveHerve Membre
    14:03 modifié #10
    Ouf, j'y suis arrivé. Encore une fois, merci pour votre aide et pour vos conseils.  :)

    J'ai fait une classe NSView spéciale pour la première série de boutons, une autre pour la seconde série, l'AppController est maintenant un NSObject, j'ai mis le second NSView en IBOutlet de l'AppController et du premier, et maintenant tout marche comme il le faut.

    Céroce, tu as peut-être raison concernant ma façon de compliquer les choses, mais une des raisons qui me porte vers Cocoa est la possibilité de créer des interfaces graphiques évoluées. Aussi autant apprendre à  le faire tout de suite...

    A ce sujet, Quartz a l'air puissant dans ce domaine. La doc montre des graphiques genre Interface Builder pour Quartz. Connaà®triez-vous une doc en français pour manipuler cela? (Ou bien je n'ai pas bien lu, ce qui est possible : je n'ai que survolé ce document)

    Merci encore à  tous. Votre site est super par ailleurs, une fois acquis un peu de métier, j'essaierai d'aider à  mon tour.

  • CéroceCéroce Membre, Modérateur
    14:03 modifié #11
    dans 1296143813:

    une des raisons qui me porte vers Cocoa est la possibilité de créer des interfaces graphiques évoluées. Aussi autant apprendre à  le faire tout de suite...

    Disons que c'est ce qu'il y a de plus difficile à  faire. Tant que tu utilises des contrôles standard, c'est facile, mais leur personnalisation est difficile parce qu'Apple ne documente pas la manière de s'y prendre.
    Ce n'est sûrement pas par ce bout-là  que je conseillerais d'aborder Cocoa.

    dans 1296143813:

    A ce sujet, Quartz a l'air puissant dans ce domaine. La doc montre des graphiques genre Interface Builder pour Quartz.

    Tu parles de Quartz Composer ? ça n'a pas grand chose avec Quartz, hormis le nom.
    Quartz Composer se trouve dans Developer/Applications. Les "compositions" peuvent être utilisées dans un projet Cocoa.
    C'est par exemple utilisé dans PhotoBooth.
  • HerveHerve Membre
    14:03 modifié #12
    Oui, je parlais de Quartz composer. J'ai lu des tutos dessus sur Internet : cela n'a pas l'air d'être trop difficile à  manier. Cela me rappelle les synthés type Reaktor ou SynthEdit pour le son, des systèmes modulaires avec lesquels il est facile d'expériementer.

    Je pense qu'ensuite, Quartz Composer donne une animation intégrable dans un autre soft?

    Sinon, je me fais peu à  peu à  Cocoa. J'aime bien. Interface Bulder, lorsqu'on l'utilise "normalement" est également une bonne idée. En Java, bon nombre de projets prenaient plusieurs centaines de lignes de code simplement pour implémenter l'interface!!! Il n'y a pas à  dire, IB est bienvenu.
  • CéroceCéroce Membre, Modérateur
    14:03 modifié #13
    dans 1296419969:

    Je pense qu'ensuite, Quartz Composer donne une animation intégrable dans un autre soft?


    Oui, un exemple avec Pulp Motion.
Connectez-vous ou Inscrivez-vous pour répondre.