2010-12-15 51 views
0

Comment puis-je faire une tableview avec 2 colonnes (x et y) pour une fonction de y = mxTableview avec 2 colonnes y = exemple mx

Ive a essayé beaucoup de choses, tous qui se terminent par un échec complet. Quelqu'un peut-il s'il vous plaît me faire un exemple de code et l'expliquer. Ive demandé et demandé et les gens m'ont dirigé vers toutes sortes de tutoriels de bool, et comment copier et coller des contenus, comment enregistrer dans un fichier, comment faire une liste des applications ouvertes, qui ne m'aident parce qu'ils sont trop compliqués

j'ai ce

//array.m 

    #import "array.h" 

    @implementation array 

    - (IBAction)makeArrays:(id)sender 
{ 
    int x,y; 
    NSNumber *multiplier=[NSNumber numberWithFloat:[mField floatValue]]; 

    for (x=0;x++;x<181) 
    { 
     y=[multiplier floatValue]*x; 

     NSNumber *xValue = [NSNumber numberWithInt:x]; 
     NSNumber *yValue = [NSNumber numberWithInt:x]; 

    NSArray *xArray = [NSArray arrayWithObject:xValue]; 
    NSArray *yArray = [NSArray arrayWithObject:yValue]; 
    } 
} 

@end 

et fichier de classe

//array.h 

#import <Cocoa/Cocoa.h> 

@interface array : NSObject { 
IBOutlet id mField; 
} 
- (IBAction)makeArrays:(id)sender; 

@end 

où dois-je aller d'ici?

+0

Il n'est pas nécessaire de continuer à basculer entre NSNumber et float comme dans makeArrays. – outis

Répondre

1

La première chose à faire dans la POO est de considérer les classes d'objets. Cocoa utilise une architecture MVC (Model, View, Controller), les classes doivent donc correspondre à l'une de ces trois catégories. Cocoa fournit déjà la classe NSTableView qui fonctionne assez bien, ce qui laisse le modèle et le contrôleur.

Il y a un certain nombre d'approches différentes de la classe de modèle que vous pourriez prendre:

  • Vous pouvez écrire une classe de table de fonction qui contient les valeurs de x et y dans des tableaux distincts
  • Vous pouvez écrire une table de fonction classe qui a un seul tableau de paires (x, y). Dans cette implémentation ou dans l'implémentation précédente, vous pouvez fournir une interface publique qui prend en charge les deux arrangements (c.-à-d. Qu'ils ont des méthodes renvoyant ay avec x et des propriétés x, y et (x, y) collections). Certains détails d'implémentation dépendent de la façon dont vous connectez la vue de la table aux données (liaisons, ou l'ancien NSTableViewDataSource protocol). Vous pouvez également utiliser un tableau de valeurs x et créer un value transformer. Avec cette approche, les valeurs y existent dans la vue tabulaire et non dans le modèle.
  • Et ainsi de suite

Les exigences d'application détermineront l'approche à adopter. Je vais vous montrer l'approche du transformateur de valeur, car elle nécessite le moins de code.

Pour le contrôleur, vous pouvez compter sur NSArrayController (qui fonctionne plutôt bien avec NSTableView) ou créer le vôtre. Par exemple, vous pouvez utiliser un NSMutableArray comme modèle et créer un contrôleur qui mappe les valeurs du tableau à d'autres valeurs. Ce contrôleur peut effectuer le mappage à l'aide de blocs ou de certaines classes de fonctions que vous définissez.

Comme vous le voyez, il y a pas mal d'options. Je vais aller avec l'option qui nécessite le moins de codage: un transformateur de valeur, un NSArrayController pour le contrôleur et un NSMutableArray (stocké dans un objet qui stocke également un transformateur de valeur) pour le modèle. Dans ce qui suit, le code devrait être stocké dans des fichiers suivant la convention standard: chaque interface et implémentation est dans un fichier séparé avec un nom égal à la classe, et une extension de ".h" pour les interfaces et ".m" pour l'implémentation.Je ne vais pas non plus me soucier des instructions d'importation courantes, telles que Cocoa/Cocoa.h et la propre interface de chaque implémentation de classe.

D'abord, le transformateur de valeur. En fait, il y en a deux, une superclasse abstraite et une sous-classe concrète. Cette séparation est telle que vous pouvez facilement ajouter d'autres types de fonctions plus tard. La superclasse, FunctionTransformer, est très simple. Tout ce qui doit être substituée à partir de sa base, NSValueTransformer, est la méthode qui retourne la classe de valeurs transformées, transformedValueClass:

@interface FunctionTransformer : NSValueTransformer 
+ (Class)transformedValueClass; 
@end 

@implementation Function 
+ (Class)transformedValueClass { 
    return [NSNumber class]; 
} 
@end 

La sous-classe concrète, LinearTransformer, doit remplacer la méthode primaire des transformateurs de valeur: transformedValue:. Puisque les transformées linéaires sont inversibles, nous fournissons également un reverseTransformedValue:. Il aura également besoin de propriétés pour les valeurs de pente et d'interception.

#import "FunctionTransformer.h" 

@interface LinearTransformer : FunctionTransformer { 
    NSNumber *m_; 
    NSNumber *b_; 
} 
@property (nonatomic,retain) NSNumber *slope; 
@property (nonatomic,retain) NSNumber *intercept; 


+ (BOOL)allowsReverseTransformation; 

-(id)init; 
-(id)initWithSlope:(float)slope; 
-(id)initWithIntercept:(float)intercept; 
-(id)initWithSlope:(float)slope intercept:(float)intercept; 

-(void)dealloc; 

-(NSNumber*)transformedValue:(id)value; 
-(NSNumber*)reverseTransformedValue:(id)value; 
@end 


@implementation LinearTransformer 
@synthesize slope=m_, intercept=b_; 

+(BOOL)allowsReverseTransformation { 
    return YES; 
} 
-(id)initWithSlope:(float)m intercept:(float)b { 
    if ((self = [super init])) { 
     m_ = [[NSNumber alloc] initWithFloat:m]; 
     b_ = [[NSNumber alloc] initWithFloat:b]; 
    } 
    return self;  
} 

-(id)init { 
    return [self initWithSlope:1.0 intercept:0.0]; 
} 
-(id)initWithSlope:(float)slope { 
    return [self initWithSlope:slope intercept:0.0]; 
} 
-(id)initWithIntercept:(float)intercept { 
    return [self initWithSlope:1.0 intercept:intercept];  
} 


-(void)dealloc { 
    [b release]; 
    [m release]; 
    [super dealloc]; 
} 


-(NSNumber*)transformedValue:(id)value { 
    return [NSNumber numberWithFloat:([value floatValue] * [m floatValue] + [b floatValue])]; 
} 

-(NSNumber*)reverseTransformedValue:(id)value { 
    return [NSNumber numberWithFloat:(([value floatValue] - [b floatValue])/[m floatValue])]; 
} 
@end 

A LinearTransformer spécifiques doit être enregistré à utiliser pour que vous puissiez régler la pente et l'interception. Le délégué de l'application peut posséder ce transformateur (avec la collection de valeurs x), ou vous pouvez écrire un contrôleur personnalisé. Nous allons écrire une classe de modèle qui regroupe les valeurs x et le transformateur de valeur, nommé FunctionTable. Le paramétrage du transformateur de fonction nécessite une sous-tâche: enregistrer le transformateur en tant que transformateur de valeur (en utilisant +setValueTransformer:forName:). Cela signifie que nous devrons fournir notre propre setter (setF:) pour la propriété du transformateur de fonction (f).

#import "FunctionTransformer.h" 

extern NSString* const kFunctionTransformer; 

@interface FunctionTable : NSObject { 
    NSMutableArray *xs; 
    FunctionTransformer *f; 
} 
@property (nonatomic,retain) IBOutlet NSMutableArray *xs; 
@property (nonatomic,retain) IBOutlet FunctionTransformer *f; 
@end 

// FunctionTable.m: 
#import "LinearTransformer.h" 

NSString* const kFunctionTransformer = @"Function Transformer"; 

@implementation FunctionTable 
@synthesize xs, f; 

-(id) init { 
    if ((self = [super init])) { 
     xs = [[NSMutableArray alloc] init]; 
     self.f = [[LinearTransformer alloc] init]; 
     [f release]; 
    } 
    return self; 
} 
-(void)dealloc { 
    [f release]; 
    [xs release]; 
    [super dealloc]; 
} 

-(void)setF:(FunctionTransformer *)func { 
    if (func != f) { 
     [f release]; 
     f = [func retain]; 
     [NSValueTransformer setValueTransformer:f forName:kFunctionTransformer]; 
    } 
} 
@end 

Par défaut, FunctionTable utilise un LinearTransformer. Si vous souhaitez en utiliser un autre, définissez simplement la propriété f de FunctionTables. Vous pouvez le faire en Interface Builder (IB) by using bindings. Notez que dans cette implémentation simpliste, le transformateur de valeur est toujours enregistré sous le nom "Function Transformer", vous limitant effectivement à un FunctionTable. Un schéma plus complexe consisterait à donner à chaque FunctionTable son propre nom de transformateur de fonction qui serait utilisé lors de l'enregistrement de son propre .

Pour tout mettre en place:

  1. Ouvrir la fenêtre principale pointe de l'application dans IB.
  2. Instancier un NSArrayController et un FunctionTable (et votre délégué d'application personnalisé, le cas échéant).
  3. Dans la fenêtre principale, ajoutez:
    1. Boutons pour ajouter et supprimer des éléments,
    2. étiquettes et NSTextFields pour la pente et l'interception,
    3. un NSTableView.
  4. Définissez les en-têtes de table à « x » et « y » (pas nécessaire pour l'application au travail)
  5. Mettre en place le connections:
    • Demandez l'ajouter & supprimer des boutons envoyer à add: de NSArrayController et remove: actions.
    • Liez les valeurs NSTextFields aux chemins de clé f.slope et f.intercept de FunctionTables.
    • Liez les valeurs des deux colonnes de NSTableView aux xs de FunctionTables.
    • Définissez le transformateur de valeur de la deuxième colonne sur "Transformateur de fonction"
    • Liez le tableau de contenu de NSArrayController à la clé xs de la table FunctionTable.
    • Si vous disposez d'un délégué d'application, connectez-le à la prise delegate du propriétaire du fichier.

maintenant construire et exécuter. Vous pouvez utiliser les boutons Ajouter et Supprimer pour ajouter et supprimer des lignes de/vers la table. Vous pouvez éditer la colonne "x" et "y" dans une rangée (ce dernier est grâce à reverseTransformedValue:). Vous pouvez trier soit par les colonnes "x" ou "y". Vous pouvez modifier la pente et l'interception, même si vous ne remarquerez pas les mises à jour dans la table, sauf si vous sélectionnez les lignes individuellement.

Sujets Recherche avancée

Pour corriger l'affichage du tableau problème de mise à jour, nous avons besoin de propager les modifications sur un propriétés d'un objet (un FunctionTransformer) aux changements sur d'un autre (un FunctionTable) propriétés. Nous aurons les changements FunctionTableobserve sur les propriétés de son transformateur de fonction et, quand il FunctionTable reçoit un avis que l'une de ces propriétés a changé, envoyer un avis que la propriété xs a changé (ce qui est un peu abusif, car xs hasn ' t effectivement changé). Cela va devenir un peu magique, alors supportez-moi.

Un objet souscrit à des modifications sur un autre objet à l'aide de la méthode KVOaddObserver:forKeyPath:options:context: de l'autre objet et se désinscrit à l'aide de removeObserver:forKeyPath:. Ces méthodes ont juste besoin d'être appelées, pas écrites. Les notifications sont gérées par une méthode observeValueForKeyPath:ofObject:change:context: de l'objet observant. Cette méthode doit donc être écrite. Enfin, un objet peut envoyer ses propres notifications en appelant willChangeValueForKey: et didChangeValueForKey:. D'autres méthodes existent pour envoyer des notifications que seule une partie d'une collection a changé, mais nous ne les utiliserons pas ici. Notre FunctionTable peut gérer l'abonnement de modification et la désinscription, mais il doit ensuite savoir quelles propriétés du transformateur de fonction observer, ce qui signifie que vous ne pouvez pas changer le type du transformateur. Vous pouvez ajouter des méthodes à chaque transformateur de fonction concrète pour vous abonner et désabonner un observateur:

@implementation LinearTransformer 
... 
-(void)addObserver:(NSObject *)observer 
        options:(NSKeyValueObservingOptions)options 
        context:(void *)context 
{ 
    [self addObserver:observer 
      forKeyPath:@"slope" 
       options:options 
       context:context]; 
    [self addObserver:observer 
      forKeyPath:@"intercept" 
       options:options 
       context:context]; 
} 
-(void)removeObserver:(id)observer { 
    [self removeObserver:observer forKeyPath:@"slope"]; 
    [self removeObserver:observer forKeyPath:@"intercept"]; 
} 
@end 

Cependant, cela nécessitera un peu juste de la répétition de code dans chaque méthode et à travers chaque transformateur de fonction béton. En utilisant la magie (reflection et closures, ou comme on les appelle en Objective-C, blocks ([2])), on peut ajouter les méthodes (appelées addObserver:options:context: et removeObserver:, car ils sont fonctionnellement similaires aux méthodes KVO pour vous abonner & désabonnement) à FunctionTransformer, ou même à NSObject. Puisque l'observation de toutes les propriétés d'un objet n'est pas limitée à FunctionTransformer, nous allons ajouter les méthodes à NSObject. Pour que cela fonctionne, vous aurez besoin de OS X 10.6 ou PLBlocks et OS X 10.5.

Commençons par le haut, avec les changements à FunctionTable. Il y a maintenant de nouvelles sous-tâches lors de la définition du transformateur de fonction: désabonnement des modifications apportées à l'ancien transformateur et abonnement aux modifications du nouveau.La méthode setF: doit donc être mise à jour pour utiliser les nouvelles méthodes de NSObject, qui seront définies dans un en-tête nommé "NSObject_Properties.h". Notez que nous n'avons pas encore à nous soucier de l'implémentation de ces méthodes. Nous pouvons les utiliser ici, en ayant la foi que nous écrirons des implémentations appropriées plus tard. FunctionTable a également besoin d'une nouvelle méthode pour gérer les notifications de modification (le observeValueForKeyPath:ofObject:change:context: mentionné plus haut). Nous écrivons ensuite les nouvelles méthodes sur NSObject. Les méthodes pour vous abonner ou vous désabonner des modifications vont boucler sur les propriétés de l'objet, donc nous allons vouloir une méthode d'assistance, forEachProperty, pour effectuer la boucle. Cette méthode d'assistance prendra un bloc qu'elle appelle sur chaque propriété. Les méthodes d'abonnement et de désabonnement appellent simplement forEachProperty, en passant un bloc qui appelle les méthodes KVO standard (addObserver:forKeyPath:options:context: et removeObserver:forKeyPath:) sur chaque propriété pour ajouter ou supprimer des abonnements.

//NSObject_Properties.h 
#import <Cocoa/Cocoa.h> 
#import <objc/runtime.h> 

@interface NSObject (Properties) 
typedef void (^PropertyBlock)(objc_property_t prop, NSString *name); 
-(void)forEachProperty:(PropertyBlock)block; 

-(void)addObserver:(id)observer options:(NSKeyValueObservingOptions)options context:(void *)context; 
-(void)removeObserver:(id)observer; 
@end 

// NSObject_Properties.m: 
... 
@implementation NSObject (Properties) 
-(void)forEachProperty:(PropertyBlock)block { 
    unsigned int propCount, i; 
    objc_property_t * props = class_copyPropertyList([self class], &propCount); 
    NSString *name; 

    for (i=0; i < propCount; ++i) { 
     name = [[NSString alloc] 
        initWithCString:property_getName(props[i]) 
        encoding:NSUTF8StringEncoding]; 
     block(props[i], name); 
     [name release]; 
    } 

    free(props); 
} 

-(void)addObserver:(NSObject *)observer 
      options:(NSKeyValueObservingOptions)options 
      context:(void *)context 
{ 
    [self forEachProperty:^(objc_property_t prop, NSString *name) { 
     [self addObserver:observer 
       forKeyPath:name 
        options:options 
        context:context]; 

    }]; 
} 
-(void)removeObserver:(id)observer { 
    [self forEachProperty:^(objc_property_t prop, NSString *name) { 
     [self removeObserver:observer forKeyPath:name]; 
    }]; 
} 
@end 
+0

ive juste essayé de le faire. ça ne marche pas. juste beaucoup d'erreurs. – ash

+0

Ive a travaillé par le biais de ce que je peux le mieux, il est très utile, sauf que je reçois beaucoup d'erreurs de compilateur. Aussi, ce n'est pas tout à fait ce dont j'ai besoin. Je n'ai pas besoin d'être en mesure d'entrer manuellement des valeurs ou de les supprimer, ou d'inverser la transformation. J'ai juste besoin que la table me donne automatiquement 180 valeurs de x augmentant de 1 à chaque fois avec son nombre correspondant pour y. Dans mon programme actuel, je n'ai pas besoin d'interception non plus. Merci pour l'aide en tout cas. Je dois aller chercher un livre ou trouver un conférencier sur le campus pour m'apprendre. Malheureusement, tous mes livres sont obsolètes et tous les tutoriels que je peux trouver sont pour xcode 2 – ash

+0

En ce qui concerne les erreurs, rappelez-vous que vous devez cibler 10.5 pour la version de base et 10.6 pour l'avancé. Si vous ciblez un SDK plus ancien, vous obtiendrez des erreurs. Vous devrez également vous assurer d'inclure les fichiers appropriés. Lorsque vous créez de nouveaux fichiers pour les classes Objective-C depuis XCode, vous devez ajouter les instructions d'importation standard (celles que j'ai ignorées). En ce qui concerne les fonctionnalités supplémentaires, la plupart sont venus gratuitement. Il aurait fallu plus de travail pour ne pas l'inclure. L'ordonnée à l'origine était un peu plus de travail, mais pas beaucoup (seulement 4 lignes et 4 caractères, plus quelques widgets dans le NIB). Alors qu'est-ce que c'est? – outis