# Echange d'info entre objets



## tommyaltaïr (3 Juin 2011)

Bonjour, 
J'ai écrit un application qui affiche une image dans une fenêtre ainsi que les coordonnées d'un clic sur cette image.
J'aimerai afficher une portion de cette image dans une autre fenêtre en utilisant le clic de la souris, définissant un rectangle centré sur le point du clic.

La structure du programme est ainsi :

```
@implementation GUIControl

- (void) awakeFromNib
{							
}

- (IBAction)preView:(id)sender
{
}

- (void) myShow
{
}
@end

@implementation MainImageView

- (void) mouseDown:(NSEvent *) theEvent
	{
	NSPoint where = [self convertPoint:[theEvent locationInWindow] fromView:nil];  				
	}
	
@end
```

GUIControl est une class que j'ai créé.
MainImageView est une class de type NSImageView.

J'aimerai utiliser "where" dans GUIControl.

Comment faire ?

Merci pour vos réponses.


----------



## ntx (3 Juin 2011)

Un contrôleur connaît la vue qu'il contrôle (fonction "view"). Donc deux solutions : 

1/ dans "awakeFromNib" tu peux créer le lien inverse pour que la vue connaisse son contrôleur et quand "where" est calculé, la vue envoie l'info à son contrôleur. Le pattern "observateur" sera le bien venu pour que le contrôleur soit notifié sur une mise à jour de "where".

2/ ou tu stockes "where" quand il est calculé et le contrôleur interroge sa vue quand il a en besoin

Je pencherais pour la première solution est le DP qui va bien.


----------



## tommyaltaïr (4 Juin 2011)

" 1/ dans "awakeFromNib" tu peux créer le lien inverse pour que la vue connaisse son contrôleur et quand "where" est calculé, la vue envoie l'info à son contrôleur. Le pattern "observateur" sera le bien venu pour que le contrôleur soit notifié sur une mise à jour de "where"".

Cela correspond t'il à une connexion inverse  dans InterfaceBuilder ?
Est il possible d'avoir un exemple ?


"2/ ou tu stockes "where" quand il est calculé et le contrôleur interroge sa vue quand il a en besoin"

La variable "where" n'est visible que dans l'implémentation de MainImageView. Je suppose qu'il faut que je définisse une variable Global. Comment fait on cela ?


----------



## ntx (4 Juin 2011)

tommyaltaïr a dit:


> Cela correspond t'il à une connexion inverse  dans InterfaceBuilder ?
> Est il possible d'avoir un exemple ?


Non, pas forcement. Tu peux implémenter une mécanique observateur/observable.


> La variable "where" n'est visible que dans l'implémentation de MainImageView. Je suppose qu'il faut que je définisse une variable Global. Comment fait on cela ?


Là je pense que tu ne maîtrises pas de tout la programmation objet.  Pour accéder en lecture/écriture à une variable interne, il suffit d'ajouter des fonctions accesseur get/set.
La variable globale est à *bannir* d'une programmation objet propre.


----------



## tommyaltaïr (9 Juin 2011)

Slt NTX,
J'ai fait quelques recherches et j'ai trouvé ce code :

Model.h

```
#import <Foundation/Foundation.h>

@interface Model: NSObject
{
	double acc;
}

-(void) setAcc: (double) value;
-(void) clear;
-(double) acc;
-(void) add: (double) value;
-(void) mul: (double) value;
-(void) sub: (double) value;
-(void) div: (double) value;
@end
```

Model.m

```
#import "Model.h"

@implementation Model

-(void) setAcc: (double) value {acc = value;}

-(void) clear {acc = 0;}

-(double) acc {return acc;}

-(void) add: (double) value {
[self setAcc: ([self acc] + value)];   // style pur objet
}

-(void) mul: (double) value{
	acc *= value;                         // style plus classique
}

-(void) sub: (double) value {acc -= value;}

-(void) div: (double) value {acc /= value;}

@end
```

Calc.m

```
#import "Model.h"

int main (int argc, const char *argv[]) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	Model *calc = [[Model alloc] init];
	[calc setAcc: 100];
	[calc add: 200];
	[calc div: 2];
	[calc mul: 5];
	NSLog(@"acc = %f", [calc acc]);
	[calc release];
	
    [pool drain];
    return 0;
}
```

Ce code introduit il une autre façon d'échange entre objet ?
Récupérer les coordonnées d'un clic sur une image ?
je me questionne sur la façon de le faire :  
                  - awakeFromNib (jai cru comprendre que cette méthode s'exécutait qu'une fois)
                  - tu stockes "where" quand il est calculé et le contrôleur interroge sa vue quand il a en besoin"
                  - ou l'utilisation du code fourni en exemple


----------



## ntx (9 Juin 2011)

tommyaltaïr a dit:


> Ce code introduit il une autre façon d'échange entre objet ?


Je ne vois où ce code introduit une discussion entre deux objets vu qu'il y en un seul d'instancié, calc.

Franchement, avant de te lancer dans Cocoa et les IHM, commence déjà par apprendre à programmer.  La programmation d'interfaces graphiques ne peut se faire sans les bases. Cela fait appel à des notions très avancées de programmation objet, et toi tu ne possèdes même pas la base de la base.  As-tu seulement la moindre idée de la façon d'utiliser un pointeur pour référencer un objet ?


----------



## tommyaltaïr (9 Juin 2011)

C'est pour cela que je fait appel aux forums.
Je souhaite vraiment parfaire mes connaissances dans ce domaine.
J'ai lu quelques documents sur le site developer d'Apple
As tu un lien à me proposer ?

Pour les pointeurs, j'utiliserai NomduPointeur.ChampsduPointeur


----------



## ntx (9 Juin 2011)

tommyaltaïr a dit:


> As tu un lien à me proposer ?


Les liens pour apprendre le C, l'Obj-C et Cocoa ont déjà été donnés mille fois. Fais une recherche  


> Pour les pointeurs, j'utiliserai NomduPointeur.ChampsduPointeur


Tu n'as même pas compris la question ... Connais-tu la différence entre valeur et adresse ? Sais-tu ce qu'es un pointeur ? As-tu seulement appris le C avant de te lancer dans Cocoa ?


----------



## tommyaltaïr (10 Juin 2011)

Le constat est partagé, j'ai à apprendre encore et encore.
Sans trop vouloir la ramener, j'ai modifié un driver PCI et son UserClient
afin d'afficher des images couleurs de 20000 par 12000 pixels d'un scanner de document que
j'ai réalisé de mes petites mains, alors les pointeurs...C'est pas ce truc qui contient l'adresse d'un autre truc ?
Merci pour ton aide.


----------



## Nyx0uf (10 Juin 2011)

Modifier un driver et galérer sur des pointeurs, c'est franchement pas triste


----------



## tommyaltaïr (29 Juin 2011)

Bonjour,
Merci pour vos réponses construites...
Cherchant ici et là et utilisant les mots clef qui m'ont été servi, je suis tombé sur NSNotificationCenter qui m'a permis de résoudre mon problème.

http://juliuspaintings.co.uk/cgi-bin/paint_css/animatedPaint/017-Comunicate-Two-Views.pl


----------



## ntx (29 Juin 2011)

tommyaltaïr a dit:


> Cherchant ici et là et utilisant les mots clef qui m'ont été servi, je suis tombé sur NSNotificationCenter qui m'a permis de résoudre mon problème.


Tu sors l'artillerie lourde :rateau: :rateau: :rateau:
Il y a des patterns plus "élégants"


----------



## tommyaltaïr (30 Juin 2011)

> As-tu seulement appris le C avant de te lancer dans Cocoa ?



J'étais confronté a un problème, je me suis donc initié au C.
Mon approche est celle d'un autodidacte.

Et quels sont ils ces patterns plus élégants ?
Des exemples, des mots clef...


----------



## tommyaltaïr (30 Juin 2011)

Et quels sont ils ces patterns plus élégants, mis à part observateur/observable ?

En utilisant les fonctions accesseur get/set, je n'ai pas réussi à récupérer les coordonnées d'un clic sourie dans mon contrôleur. En traçant mon programme, j'ai pu m'apercevoir que la méthode getMouse de ma vue me revoyait le point de valeur 0,0 en permanence alors que les coordonnées de celui-ci étaient correctes dans la méthode mouseDown. 
Par contre, le contrôleur récupère les bonnes valeurs du point si je les fixe dans getMouse.

Je suis donc passé à NSNotificationCenter bien que les fonctions accesseur get/set me plaisent plus.


----------



## ntx (30 Juin 2011)

tommyaltaïr a dit:


> Et quels sont ils ces patterns plus élégants, mis à part observateur/observable ?


C'est très élégant comme pattern  Une grand partie des discussions entre objets dans les IHM Java fonctionne comme cela. Mais le NSNotificationCenter n'est en gros qu'une généralisation de sce pattern. Mais tu as un seul observateur qui reçoit toutes les notifications et les redistribue à ses abonnés. Il ne faut pas craindre les engorgements  La voie directe entre deux objets doit être plus rapide.


----------



## tommyaltaïr (2 Juillet 2011)

Bonjour ntx,
j'ai fait un nouvel essai avec la mécanique observateur/observable.
le programme ne fonctionne pas comme je souhaite: Quand je clic sur la NSImageView les différentes méthodes de MainImageView s'exécutent correctement avec les bonne values. Lors après, j'active un NSButton, la méthode "preView" de GUIControl s'exécute mais là, je récupère un NSPoint à 0. Si je regarde la variable "test" lorsque le programme est stoppé dans GUIControl, tous les champs sont à 0 alors qu'ils sont correctement renseignés lorsque le programme est stoppé dans MainImageView. Si je set la variable storeWhere dans awakeFromNib sans faire de clic dans la vue, les coordonnées du point sont correctes dans GUIControl. I need help.

voilà le code: 

Preview.h

```
@interface MainImageView : NSImageView
{
	NSPoint				where;
	NSPoint				storeWhere;
}
 
- (void) awakeFromNib;
- (void) mouseDown:(NSEvent *) theEvent;
- (NSPoint) mousePosition;
- (void) setPosition:(NSPoint)clic;
@end
```

Preview.m

```
@implementation MainImageView

- (void) awakeFromNib
 {
//	storeWhere.x=235;
//	storeWhere.y=238;
}

- (void) mouseDown:(NSEvent *) theEvent
	{
	where = [theEvent locationInWindow];
	[self setPosition:where];
	}
	
- (NSPoint) mousePosition
	{
	return  storeWhere;
	}

- (void) setPosition:(NSPoint)clic
	{
	storeWhere=clic;
	}

@end
```

GUIControl.h

```
@interface GUIControl : NSObject
{
	MainImageView * test;
}

- (IBAction)preView:(id)sender;

@end
```


GUIControl.m

```
@implementation GUIControl

- (void) awakeFromNib
{
	test = [[MainImageView alloc] init];						
}

- (IBAction)preView:(id)sender
{
    NSPoint crop;
    crop =[test mousePosition];
}

@end
```


----------



## ntx (2 Juillet 2011)

Ton code n'est pas tout à fait un pattern observateur/observé.
Pour ce pattern, l'observateur doit s'enregistrer auprès de son observé qui gère donc une liste de ses observateurs. Ensuite à chaque fois qu'une action est faite, l'observé doit notifier ses observateurs.

Bon, tu n'as pas tout implémenté mais ton code doit aussi marcher ... à une nuance près. Comment est créée ton instance de la classe MainImageView ? Par IB ? Car dans ce cas je pense que cette instance créée par IB et celle créée dans ta classe GUIControl ne sont pas les mêmes. Pour en être sûr, affiche les adresses de ces objets dans les différentes méthodes ou regarde au debugueur.

Dans IB, il faut définir ta vue comme étant une classe MainImageView.
Ensuite toujours dans IB tu déclares une instance de la classe GUIControl.
Dans ta classe GUIControl, tu définis un IBOutlet de type MainImageView et tu fais un lien dans IB entre tes deux instances, ta vue et son contrôleur. Et là ton contrôleur connaît la vue qu'il contrôle et il peut l'interroger.
Ensuite tu peux faire en sorte que ta vue connaisse son contrôleur : tu ajoutes dans les membres de ta classe MainImageView un pointeur du type GUIControl avec son setter, et dans la fonction GUIControl::awakeFromNib tu positionnes self sur la valeur de ce pointeur.


----------



## tommyaltaïr (6 Juillet 2011)

Merci pour ton aide NTX,
j'ai suivi tes instructions et maintenant j'ai une appli qui fonctionne.
Merci encore.

Pour ceux qui se posent des questions similaires, voilà un bon tutorial.

http://juliuspaintings.co.uk/cgi-bin/paint_css/animatedPaint/020-NSControl-NSView-At-Class.pl


----------

