Gérer une table à n colonnes sans se fatiguer à tout programmer

Le reste du projet ne change pas : chaque ligne est une entrée de la table. Il faut aussi 2 boutons : un bouton pour ajouter un élément et un autre pour supprimer une entrée. Des contrôles permettront d'afficher les valeurs d'une ligne sélectionnée.

Vous allez voir que ça n'est pas très différent de l'exemple précédent.

Commençons par créer les objets dans Interface Builder.

Dans une fenêtre, déposez un objet NSTableView pour la grille, des objets NSTextField pour les zones de saisie et NSButton pour les 2 boutons. C'est le BA-ba, je n'y reviens pas.


interface_1

Déposez ensuite un objet NSObjectController dans la fenêtre de votre fichier .NIB. Cet objet va faire le lien entre votre tableau et le contrôleur de votre application :

nsobjectcontroller

Déposez ensuite un objet NSArrayController dans la fenêtre de votre fichier .NIB. Cet objet va représenter votre tableau; vous pouvez lui donner le nom que vous voulez :

nscontrollerarray

Affichez les propriétés de cet objet et indiquez "objet" dans le champ "Object Class Name" dans la section "Attributes". Ce nom fera la liaison avec un module de classe de votre programme qui gérera le dictionnaire de données. Ne vous occupez pas pour le moment des 'Keys" de l'objet.


objectclassname

Le reste du travail va essentiellement consister à raccorder tout ce petit monde.

Cliquez sur l'icône de l'objet NSObjectController et tout en maintenant la touche [Ctrl], glissez jusqu'à l'icône du contrôleur de votre application (le cube bleu). Relachez la souris et dans la fenêtre de connexion qui s'affiche, sélectionnez la ligne "Content" et cliquez sur le bouton "Connect".


connection_1

Sélectionnez l'icône de l'objet NSArrayController et affichez les propriétés. Déroulez le menu de la fenêtre et affichez "Bindings". Déroulez la section "contentArray" et renseignez les champs comme indiqué ci-dessous. "myTable" dans le champ "Model Key Path" est le nom de la variable d'instance de votre tableau dans le programme :


bindings


Affichez l'objet NSTableView et double-cliquez deux fois sur l'entête de la première colonne pour sélectionner l'objet NSTableColumn sous-jacent. Profitez-en pour nommer l'entête de ladite colonne. Affichez ensuite les propriétés de Binding de la colonne. Dans la section value, renseignez les champs comme indiqué ci-dessous. "NSArrayController" est le nom de votre objet NSArrayController; c'est ce nom qui apparaîtra dans le menu "Bind to" si vous l'avez renommé. "properties.champ1" dans le champ "Model Key Path" détermine la structure du dictionnaire de données que vous devrez définir par un module de classe dans votre programme.


nstablecolumn_1

Faites de même avec les autres colonnes. Donnez "properties.champ2" et properties.champ3" comme valeur pour le champ "Model Key Path".

Occupons-nous maintenant des 2 boutons.

Sélectionnez le bouton prévu pour ajouter des données. Tout en conservant l'appui sur le bouton [Ctrl], glissez jusqu'à l'icône de l'objet NSArrayController. Relâchez la souris et dans la fenêtre qui s'affiche, sélectionnez l'action "add" puis cliquez sur "Connect". Faites de même avec le bouton prévu pour supprimer des éléments, mais sélectionnez l'action "remove" :


connectaction_1

Avant de pouvoir faire fonctionner votre application, Il faut ajouter la déclaration de votre tableau dans le header de votre classe contrôleur :

    NSMutableArray * mytable;


Ajoutez également un module de classe que vous appellerez "objet". Ce nom doit correspondre à ce que vous avez indiqué dans le champ "Object Class Name" de l'objet "NSArrayController". Chaque fois que vous allez ajouter une ligne de données dans votre table, le programme va créer un objet instancié à partir de cette classe et cet objet sera ajouté au tableau "myTable" déclaré dans le module contrôleur. Le tout sans presque rien programmer.

Le fichier objet.h doit contenir les lignes de code suivantes (eh oui, il y a malgré tout un peu de programmation) :

#import <Cocoa/Cocoa.h>
@interface objet : NSObject {
    NSMutableDictionary * properties;
}
@end


On déclare simplement un dictionnaire "properties" (mais oui, c'est pour ça qu'on a "bindé" les colonnes de la table à quelque chose comme "properties....").

Le module de classe "objet.m" n'est guère plus compliqué :

#import "objet.h"
@implementation objet
- (id) init
{
    if (self = [super init])
    {
        NSArray * keys      = [NSArray arrayWithObjects: @"champ1", @"champ2", @"champ3", nil];
        NSArray * values    = [NSArray arrayWithObjects: [NSString string], [NSString string], [NSString string], nil];
        properties = [[NSMutableDictionary alloc] initWithObjects: values forKeys: keys];
    }
    return self;
}
- (void) dealloc
{
    [properties release];
    [super dealloc];
}


On définit simplement les méthodes init et dealloc. La méthode init permet d'initialiser le dictionnaire qui décrit les colonnes de votre table : nom des colonnes (champ1, champ2 et champ3 dans l'exemple ou tout ce que vous voulez) et leur type et valeur initiale (un chaîne vide dans l'exemple ou tout ce que vous voulez).

Voici quelques exemples d'autres définition de colonne :

    [NSString string] pour une chaîne vide
    @"Valeur" pour une chaîne constante
    [NSDate date] pour une date initialisée avec la date du jour


Remarquez la façon dont on indique le nombre d'elément dans le dictionnaire : il n'est pas explicite et on termine la liste par "nil". Vous pouvez ainsi contruire une table avec autant de colonnes que vous voulez.

Compilez et testez. Admirez le résultat... et tout ça sans presque rien programmer !!!!

Terminons avec le binding des contrôles NSTextField. Remarquez bien que ça n'a rien d'indispensable puisque vous pouvez éditer les données directement dans la grille.

Sélectionnez l'objet NSTextField et affichez ses propriétés de Bindings. Dans la section "value", renseignez les champs comme indiqué ci-dessous. "NSArrayController" est le nom de votre objet NSArrayController; c'est ce nom qui apparaîtra dans le menu "Bind to" si vous l'avez renommé. "properties.champ1" dans le champ "Model Key Path" doit correspondre à ce que vous avez mis pour la colonne correspondante. En fait, ce paramétrage est identique à ce que vous avez fait pour la colonne sauf que "Controller Key" est "selection" au lieu de "arrangedObjects". Pour ne pas vous tromper, utilisez la liste déroulante :


nstextfield

Procédez de même avec les autres zones de saisie, mais en prenant une autre valeur pour "Model Key Path".

Recompilez l'application et testez...

Remarquez que si vous avez activé la sélection multiple dans la grille, si vous tapez une nouvelle valeur dans le contrôle de saisie, elle remplacera toutes les valeurs de la colonne correspondante dans les lignes sélectionnées.

Cerise sur le gâteau : nous allons ajouter un texte qui affichera le nombre d'éléments dans la table.

Ajoutez un objet de type "Label Font Text" (c'est un NSTextField malgré tout, mais il n'est pas éditable). Affichez ses propriétés de Bindings et dans la section "displayPatternValue1", renseignez les champs comme suit. Remarquez le champ "Model Key Path" avec la valeur spéciale "@count". Remarquez également le champ "Display Pattern" qui formate la valeur affichée.


count

Vous pourriez également afficher le nombre d'éléments sélectionnés dans la liste (utile dans le cas où vous avez activé la sélection multiple). Remplacez simplement "arrangedObjects" dans le champ "Controller Key" par "selection".

Vous pouvez télécharger le projet complet sur ma
page de téléchargement (DemoBind1.zip)