Création d’un colorimètre sous Cocoa
Dans cet article, nous allons créer une application Cocoa simple qui va nous permettre d’explorer encore plus les interactions avec les objets d’interfaces et l’obtention d’informations en provenance d’utilisateurs. Cette application est une application Cocoa standard – un colorimètre – et non une application de gestion document.
Le colorimètre n’est pas compliqué. Il consiste en une série de quatre jauges – une jauge pour le bleu, une pour le rouge, une pour le vert et une pour la couche alpha (transparence), de quatre champs texte et d’un « color well » (témoin de couleur).
Bien allons-y !
L’ interface
La classe NSControl
Dans ce projet, je vais vous présenter les objets de contrôles d’interface plus sous l’aspect de classes que sous celui d’images placées sur l’écran. Dans Cocoa, les éléments graphiques composant les interfaces sont tous des descendants de la classe abstraite NSControl de l’Application Kit.
Vous êtes sûrement familier de la forme de ces composants mais pas de leur fonction de bas niveau. Je vais passer un peu de temps sur la classe NSControl pour vous montrer comment vous pouvez prendre contrôle des composants de votre interface.
Les méthodes de NSControl sont celles que l’on utilise pour obtenir des informations de la part de l’interface telles que les chiffres et les caractères saisis dans un champ.
Les méthodes de NSControl
Les méthodes qui nous seront de la plus grande utilité pour le moment sont celles qui nous permettent de récupérer des données à partir d’un composant d’interface et de donner une valeur aux données contenues dans ces composants. NSControl détient plusieurs méthodes pour nous permettre de faire ceci. Ces méthodes sont appelées accessor methods, parce qu’elles nous permettent d’accéder aux données appartenant à des objets.
Pour obtenir un nombre ou une chaîne de caractères à partir d’un composant d’interface (contrôle), nous utilisons une des méthodes suivantes :
- doubleValue
- floatValue
- intValue
- objectValue
- stringValue
Le nom de chaque méthode indique implicitement le type de donnée retournée : double retournera un nombre de type « double », float un nombre à virgule flottante, et int un nombre entier.
Pour une chaîne de caractère nous utilisons stringValue. La méthode objectValue retournera la valeur de l’objet contenu dans la cellule du composant d’interface.
Le fait de garder les valeurs de composants d’interface sous forme d’objets simplifie la circulation des données entre les objets qui utilisent le type de données en question, sachant que la plupart des objets qui supportent des nombres ou des chaînes de caractères requièrent des types de données NSNumber ou NSString.
Pour donner une valeur à un composant d’interface, nous invoquons les méthodes suivantes :
- setStringValue:
- setDoubleValue:
- setFloatValue:
- setObjectValue:
- setIntValue:
Par exemple, si nous avions un champ texte dans lequel nous voudrions afficher un chiffre, nous enverrions le message suivant au champ en question :
[textField setDoubleValue:3.14159265358979323846];
L’argument de chaque méthodes de type setxxxValue: est du type indiqué dans le nom de la méthode (« xxx »).
Le mode de dénomination vu au-dessus pour les méthodes « accessor » est un standard de Cocoa. Vous verrez ces méthodes dans plein de classes du Kit Application et du Kit Fondation, et cela a pour avantage de ne pas avoir à retenir beaucoup de vocabulaire pour que les choses avancent. Par exemple, NSString comporte ces mêmes méthodes, dont une permet d’extraire un nombre entier d’une variable de type NSString. NSNumber comporte aussi une méthode stringValue qui permet de transformer un nombre en chaîne de caractères.
Ce mode de dénomination n’a pas été pensé uniquement pour son aspect commode. Il va encore plus loin. Beaucoup de fonctions des framework Cocoa ne fonctionneront que si ce mode est respecté. Nous n’en parlerons pas maintenant, mais si vous ne pouvez pas attendre, allez jeter un œil au « Key Value Coding », qui est décrit dans le protocole informel NSKeyValueCoding. Le texte de référence peut être trouvé dans le « Foundation Framework Class Reference », à l’adresse : NSKeyValueCoding (Objective-C) (nécessire un ADC User Id).
NSControl définit aussi plusieurs autres méthodes. Il y en a qui permette de formater du texte. D’autres de changer la police d’affichage à l’intérieur d’un composant d’interface. Vous pouvez activer ou désactiver un composant d’interface en lui envoyant un message setEnabled:YES ou setEnabled:NO (rappelez vous que YES et NO est la manière de représenter les valeurs booléennes en Objective-C). Tous les attributs d’un composant d’interface que vous réglez dans IB – y compris l’emplacement, les cibles et tout ce que vous paramétré dans la panneau Info – peuvent être changés dans le code.
Avec les méthodes comprises dans NSControl, vous pouvez avoir un contrôle total sur tous les aspects liés à vos composants d’interface. Si vous voulez voir une description complète de ce que les méthodes de NSControl ont à offrir, y compris toutes les méthodes disponibles de cette classe, prenez connaissance du document de référence à l’adresse : NSControl (Objective-C).
Construction de notre interface
Maintenant que nous savons comment œuvrer avec nos contrôles, construisons notre interface et écrivons en le code pour notre plus grand plaisir.
L’interface du colorimètre consiste en quatre jauges, quatre champs texte qui servent d’étiquettes, quatre champs texte qui affichent du texte de manière dynamique et, un témoin de couleur.

L’interface du colorimètre.
Les champs texte peuvent être trouvés dans la palette « Cocoa-Views ». L’interface de notre application utilise deux de ceux qui s’y trouvent. Sur la gauche, il y a un rectangle blanc vierge. C’est un champ texte qui permet à l’utilisateur d’y rentrer des caractères. Il y a aussi un champ qui indique « Informational Text ».
Ces deux champs texte sont des instances de la même classe NSTextField. Ils différent seulement au niveau des options d’affichage, de police et d’actions utilisateur. En fait, il est possible de les interchanger au travers des attributs du panneau « Info » ou au travers du code. Dans Cocoa, vous avez un total contrôle sur les éléments de l’interface.
Maintenant, faites glisser chacun de ces éléments vers la fenêtre principale, ne vous souciez pas de leur organisation tant que les jauges ne sont pas en place. Les jauges sont localisées dans la palette « Other Cocoa Views ». Vous y trouverez plusieurs types de jauges. Là encore, la situation est la même qu’avez les champs texte. Vous pouvez changez l’apparence de chaque jauge en agissant sur les attributs ou sur le code.
La dernière chose dont nous avons besoin dans la palette actuelle est le témoin de couleur. Faites le glisser quelque part sur l’interface au meilleur endroit. Vous avez ci-dessus l’apparence que j’ai donnée à la mienne. Organisez la comme bon vous semble.
Repères de dessin
IB fournit plusieurs outils pour vous aider à aligner rapidement vos objets en conformité avec le Guide de l’Interface Humaine Aqua. Nous avons parlé de l’un d’entre eux auparavant : les lignes repères qui s’affichent quand on bouge les composants de l’interface.
Par défaut, quand vous déplacez un objet près d’un autre, certains repères apparaîtront pour vous indiquer la distance de séparation et l’alignement idéal. Vous pouvez donner plus de puissance à cette fonction en activant les rectangles de positionnement (« Layout Rectangles ») dans le menu « Layout » (mise en page) ou en pressant Commande-L. Ces rectangles fournissent une commodité supplémentaire : les objets se bloquent momentanément quand ils s’approchent des emplacements Aqua idéaux.

Vous pouvez activer le calibrage Aqua en activant les « Layout Rectangles ».
Si vous désirez obtenir encore plus de précisions lors du placement de vos composants, vous pouvez déplacer les objets sélectionnés en vous servant des flèches directionnelles du clavier. Une simple pression de touche dans n’importe quelle direction déplacera l’objet d’un pixel dans cette direction. Si vous maintenez la touche « Option » enfoncée et passez au dessus d’un autre objet tandis qu’un premier objet est sélectionné, des informations relatives à la distance de séparation en pixels s’afficheront alors. L’objet sélectionné peut alors dans ce cas être déplacé avec les touches directionnelles.

Si vous maintenez la touche « Option » enfoncée et passez au dessus d’un autre objet tandis qu’un premier objet est sélectionné, des informations relatives à la distance en pixels de séparation des deux objets s’afficheront alors.
Finalement, si vous préférez plus d’automatismes, vous trouverez un outil d’alignement dans le menu « Tools » qui a plusieurs options d’alignement de groupes d’objets, comme tout programme de dessin.

Pour plus d’automatismes, utilisez l’outil d’alignement.
Réglage des attributs des objets
Avant de continuer avec l’interface, changeons le comportement des jauges. Ouvrez l’Inspecteur pour voir les attributs des objets. Celui ci vous permet de régler les attributs d’activation et les caractéristiques de certains objets d’interface. Les options dépendent du type d’objet.
Le panneau « Info » permet aussi de changer la manière de s’adapter aux redimensionnements de la fenêtre. Vous pouvez aussi y voir toutes les connections à l’objet, et même lui associer une classe personnelle.
Notre but ici est de changer la manière dans laquelle les jauges envoient des messages aux méthodes. L’option par défaut est d’envoyer un message à quiconque est en attente de la fin de la manipulation de l’utilisateur (le moment où après avoir bougé le curseur de la jauge l’utilisateur relâche la souris).
Nous voulons que les jauges transmettent en continue des messages lorsque leur curseur est déplacé de manière à impacter la couleur qui est affichée dans le témoin. Cela est possible en activant l’option « Continuous » dans le panneau des attributs de l’inspecteur.
Une autre chose que nous pouvons changer sont les limites de la jauge, c’est à dire, les valeurs minimale et maximale correspondant aux extrémités de la jauge. Sachant que la création d’une couleur appropriée se fera en créant une instance de la classe NSColor avec des paramètres de rouge, de vert, de bleu et de couche alpha qui ne peuvent varier que de zéro à un, nous allons régler les valeurs minimale et maximale des jauges à 0 et à 1. “Current” représente la valeur initiale de l’objet. Vous pouvez lui attribuer la valeur que vous voulez, j’ai réglé les miennes à 0,5.
Nous n’allons pas modifié les comportements de nos champs de texte, mais si vous regardez de près les attributs de l’un d’entre eux, vous verrez que vous pouvez changer la police, la couleur, la taille, l’alignement et l’édition. Vous pouvez bien sûr changer ce que vous voulez, pour ma part je les ai laissé tels quels dans un soucis de simplicité.
L’objet Contrôleur
En POO (programmation orientée objet), il y a plusieurs concepts d’organisation des classes et des objets dans une application. La nôtre est simple donc son organisation le sera aussi.
Nous emploierons le concept connu sous le nom de Contrôleur de Vue de Modèle. La Vue est l’interface de votre application – les jauges, les champs et le témoin de notre application. Le Modèle est le modèle de données de notre application.
Notre application ne traite pas vraiment des données et, donc, nous n’aurons pas d’objet modèle. Le Contrôleur est un objet qui relie notre interface au modèle de données. Dans ce type de concept, l’interface de devrait rien savoir de la manière dont sont stockées et gérées les données, et le modèle ne devrait avoir aucune connaissance de la manière d’afficher l’interface. C’est à l’objet Contrôleur qu’il revient d’établir la communication entre ces deux domaines. Construisons le.
A partir de l’onglet « Classes », localisez la classe NSObject dans la liste des classes disponibles. Nous voulons créer une sous-classe d’elle. Faites ceci en sélectionnant « Subclass » dans le menu « Classes », et appelez la « Controller ».
Maintenant, ajoutez les objets et les actions tel que montré ci-dessous en leur attribuant les mêmes noms. Les nouveaux objets peuvent être créés toujours à partir du menu « Classes ».

Ajout d’objets et d’actions.
L’étape suivante consiste à créer des instances de notre nouvelle classe de manière à pouvoir connecter les prises et les actions à leur objet approprié. Leur nom devrait vous permettre de trouver la manière de les connecter. Rappelez-vous, connectez les actions en partant de l’objet interface – une jauge – et glisser le en maintenant la touche ctrl enfoncée vers l’instance du contrôleur. Les outlets sont connectées dans la direction opposée. Gardez à l’esprit d’effectuer les branchements dans la direction que prendront les messages.
Une fois que vous avez effectué les connexions, vous aurez besoin d’ajouter dans PB (Project Builder) les fichiers interface et implémentation à notre projet. Cela se fait assez facilement en retournant à l’onglet « Classes », en sélectionnant la classe « Controller », et en sélectionnant « Create Files » à partir du menu « Classes ».
Fermez Interface Builder et retournez à Project Builder.
Coding
Voici comment notre colorimètre opère. L’utilisateur déplace les curseurs des jauges relatives à chacune des couleurs primitives. En même temps, les nouvelles valeurs de chaque jauge sont indiquées dans les champs texte respectifs à gauche de chaque jauge. Maintenant, ce que nous avons à faire et de fournir le code qui affichera une couleur dans le témoin en fonction des états de chaque jauge.
La première chose à faire est de déclarer quatre variables d’instances de type « float » (virgule flottante) dont le but sera de stocker la valeur de chaque composant. Dans le fichier interface Controller.h insérez les variables suivantes après les variables d’instances de IBOutlet :
float redValue;
float greenValue;
float blueValue;
float alphaValue;
Maintenant, nous devons ajouter à cette classe une méthode dont le but sera de mettre à jour la couleur affichée dans le témoin. Cette méthode sera :
- (void)updateColor;
Ainsi, notre code devrait ressembler à ça :
#import <Cocoa/Cocoa.h>
@interface Controller : NSObject
{
IBOutlet id alphaField;
IBOutlet id alphaSlider;
IBOutlet id blueField;
IBOutlet id blueSlider;
IBOutlet id colorWell;
IBOutlet id greenField;
IBOutlet id greenSlider;
IBOutlet id redField;
IBOutlet id redSlider;
float redValue;
float greenValue;
float blueValue;
float alphaValue;
}
- (IBAction)setAlpha:(id)sender;
- (IBAction)setBlue:(id)sender;
- (IBAction)setGreen:(id)sender;
- (IBAction)setRed:(id)sender;
- (void)updateColor;
@end
Les quatre méthodes d’actions dont le but est de fixer les composants couleur auront la même structure :
Voici le code pour setBlue:
- (IBAction)setBlue:(id)sender
{
blueValue = [sender floatValue];
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
[self updateColor];
}
A la première ligne nous demandons à l’émetteur (« sender ») qui a lancé une requête à la méthode setBlue pour lui demander la valeur de type « float » (floatValue) de sa donnée, puis de la stocker dans blueValue. Dans ce cas, l’émetteur peut être l’un des deux objets de l’interface (le champ texte ou la jauge).
Si vous vous rappelez, nous avons branché la jauge bleue et le champ texte correspondant à la même action. En fonction de l’intervention de l’utilisateur, l’un ou l’autre de ces objets peut être l’émetteur du message invoquant cette méthode. Ceci est dans la nature de toutes les méthodes IBAction. En fait, l’argument de la méthode d’action est l’objet émetteur. Cela facilite l’obtention d’information à partir de l’interface et permet de maintenir une bonne dose de flexibilité dans notre code, tel qu’illustré ci-dessus. Cela veut aussi dire que nous n’avons pas besoin d’écrire une méthode d’action supplémentaire pour intervenir sur un composant supplémentaire. Nous pouvons ajouter autant de composants d’interface que l’on veut pour agir sur valeur de la couleur bleu et les connecter tous à la même action. C’est aussi la puissance du polymorphisme, tout comme le fait que tous les composants d’interface Cocoa répondent de la même manière à la méthode floatValue, en retournant un nombre de type virgule flottante.
Le but des deux lignes du milieu est de synchroniser les valeurs affichées dans la jauge et dans le champ texte. Ainsi, si la jauge est l’émetteur, le champ texte prendra la valeur appropriée et vice versa. La méthode setFloatValue: fait exactement le contraire de floatValue. Là où floatValue retourne la valeur du composant d’interface sous forme de nombre décimal, setFloatValue: prend un nombre décimal comme argument et attribue cette valeur au composant d’interface.
La dernière ligne indique simplement à l’objet contrôleur (même si cette méthode s’envoie un message à elle même) de mettre à jour la couleur affichée dans le témoin. Nous aurions pu mettre le code approprié pour mettre à jour le témoin dans chaque méthode « set…», mais un des buts de la POO est de réutiliser le moins de code possible. Ainsi, en extrayant le code de mise à jour de chaque méthode « set… », en le plaçant dans une autre méthode, et en plaçant un appel dans chacune des méthodes, nous optimisons le code. L’avantage évident de cette façon de faire est d’éviter de modifier quatre fois le code (dans chaque méthode) si l’on veut y apporter des améliorations.
Les commandes setGreen:, setRed:, et setAlpha sont exactement les mêmes que la commande setBlue:, excepté à chaque endroit où vous rencontrez le mot Blue, vous le remplacez par le mot Red, Green, ou Alpha; et à chaque fois que vous rencontrez blue (pas de majuscule), vous le remplacez par red, green, ou alpha.
Sachant que updateColor n’est pas une méthode d’action d’IB comme les autres, nous devons la définir manuellement (c’est pourquoi nous avons du l’ajouter au fichier interface plutôt). Voici le code pour la méthode updateColor: :
- (void)updateColor
{
NSColor *aColor = [NSColor colorWithCalibratedRed:redValue green:greenValue blue:blueValue alpha:alphaValue];
[colorWell setColor:aColor];
}
Ce que nous faisons en premier est de créer une nouvelle couleur en appelant la méthode colorWithCalibratedRed: green: blue: alpha: et de stocker l’objet couleur retourné dans la variable aColor, qui est déclarée localement sur la même ligne. La méthode NSColor que nous invoquons ici est une des nombreuses disponibles pour la création de couleur. Il y a des méthodes de la classe NSColor qui retourne une couleur présente telle que redColor. Si vous voulez en savoir plus sur la classe NSColor, allez voir : NSColor (Objective-C).
Finalement, de la même manière que nous affichons un nombre dans un champ texte avec setFloatValue:, nous affichons une couleur dans l’objet témoin en lui envoyant un message setColor: en passant l’objet couleur que l’on vient de créer.
Finalement
Et voilà ! Compilez votre code (en espérant que vous n’aurez aucune erreur), lancez le et jouez avec. Si vous voulez découvrir une autre pépite de Cocoa, cliquez sur le témoin et devant vos yeux ébahis apparaîtra la pipette de couleur système. A se stade, nous n’avons ajouté aucune ligne de code pour que les champs texte et les jauges reflètent la couleur réglée dans le témoin par la pipette, mais je vous encourage à lire le texte de référence des classes dont nous avons parlées et d’y voir si vous ne pouvez pas y arriver tout seul (si vous avez un peu de mal, envoyez moi le code et on se débrouillera en ligne).

Après compilation et lancement, vous devriez avoir une interface qui ressemble à ça.
Dans les prochains articles, je ferai moins d’applications complètes et irai plus en profondeur dans les classes du “programme-cadre fondation” qui traitent des chaînes, des nombres et des ensembles. J’espère que vous apprécierez. A la prochaine fois !

http://www.macdevcenter.com/
Textes originaux en anglais sur O’Reilly : http://www.macdevcenter.com/pub/au/159
Chargement
Commentaires récents