Afficher une NSView dans une fenêtre sans passer par IB

CrazyJoCrazyJo Membre
21:48 modifié dans API AppKit #1
Salut à  tous,

Je souhaite afficher une nsview dans ma window. J'arrive à  afficher ma window et mon label mais pas ma nsview. Regardez plutôt le code suivant :
<br /><br />#import &quot;view.h&quot;<br />@implementation view<br /><br />- (void)awakeFromNib {<br />	[window setTitle:@&quot;hey&quot;];<br />	<br />	NSWindow *window2 = [[NSWindow alloc] initWithContentRect: NSMakeRect(300,300,200,200) <br />										 styleMask:(NSTitledWindowMask| <br />													NSMiniaturizableWindowMask| <br />													NSClosableWindowMask |<br />													NSResizableWindowMask) <br />										 backing&nbsp; : NSBackingStoreBuffered <br />										&nbsp;  defer&nbsp; : YES]; <br />	<br />	NSTextField *label = [[NSTextField alloc] initWithFrame: NSMakeRect(30,30,80,30)]; <br />	[label setSelectable: NO]; <br />	[label setStringValue : @&quot;Hello&quot;]; <br />	<br />	NSView *view = [[NSView alloc]initWithFrame:NSMakeRect(50,100, 100, 100)];<br />	[view setHidden:NO];<br />	<br />	<br />	<br />	[[window2 contentView] addSubview: view]; <br />	[[window2 contentView] addSubview: label]; <br />	[view release];<br />	[label release];<br />	[window2 makeKeyAndOrderFront : self]; <br />	<br />	[self setNeedsDisplay:YES];<br />}<br /><br /><br />- (void)drawRect:(NSRect)rect {<br />	NSRect cadre = NSMakeRect(50,100, 60, 40);<br />	[[NSColor greenColor]set];<br />	[NSBezierPath fillRect:cadre];<br />}<br /><br />@end<br /><br /><br />

Réponses

  • AliGatorAliGator Membre, Modérateur
    21:48 modifié #2
    A mon avis tu arrives très bien à  rajouter ta NSView.
    Mais une NSView, ça ne fait rien, c'est vide, ce n'est qu'un conteneur. Donc ça n'affiche rien à  l'écran.

    Sauf si tu sous-classes NSView, pour surcharger la méthode drawRect de NSView (pour indiquer quoi dessiner), et que c'est un objet de cette sous-classe de NSView que tu crées.

    Mais là  tu crées un NSView "standard" (pas une sous-classe) donc ça ne risque pas d'afficher quoi que ce soit.
    Après, je vois que tu as en effet une méthode "drawRect" dans ton code, mais c'est dans le code de quoi ? J'imaginer vu le nom "view" de ta classe que c'est ta sous-classe perso de NSView, donc c'est très bien... mais encore faut-il que ce soit un objet de ce type que tu crées alors dans awakeFromNib ;)
  • CrazyJoCrazyJo Membre
    21:48 modifié #3
    Donc oui c'est un NSView "standard" à  laquelle je souhaite afficher un rectangle vert grâce à  la méthode drawRect:. Le projet xCode ne comporte que ce fichier (avec le .h bien entendu*..). Dans IB j'ai simplement un objet 'view' lié à  rien du tout. (view étant le nom de ma classe NSView).
    mais encore faut-il que ce soit un objet de ce type que tu crées alors dans awakeFromNib

    Je ne comprends pas bien cette dernière phrase. Pourquoi devrais-je créer un objet de ce type dans le awakeFromNib ? Comment dois-je faire pour que ma vue qui apparemment est bien implémentée prenne en compte la méthode drawRect: ?


    *le .h au plus simple :
    @interface view : NSView {<br />}<br />
    


  • AliGatorAliGator Membre, Modérateur
    21:48 modifié #4
    bah en fait maintenant que je regarde, si j'ai vien compris ton contexte, ça c'est le code de ta classe view... qui se désarchive depuis un NIB donc.
    Mais le problème c'est que dans awakeFromNib, tu rajoutes une NSView (et pas une view, ta sous-classe), dans ta window...
    &nbsp;  NSView *view = [[NSView alloc]initWithFrame:NSMakeRect(50,100, 100, 100)];<br />...&nbsp;  <br />&nbsp;  [[window2 contentView] addSubview: view];
    
    Donc forcément, il rajoute une NSView "standard", celle d'Apple qui ne fait rien côté dessin. Et non pas une instance de ta classe "view"...
    C'est p'tet plutôt "self" que tu devrais mettre à  la place de ton objet "view" du coup, non ? (et virer la déclaration de "NSView* view = ..." plus haut) ?


    (Bon ceci dit si c'est bien ça j'ai du mal à  comprendre la logique de ton code, pourquoi tu crées la window2 et le textLabel par code mais la view par NIB, au lieu de tout mettre dans le NIB par exemple ?)
  • CrazyJoCrazyJo Membre
    21:48 modifié #5
    Je reprends :
    Je ne veux pas passer par IB. Je veux créer une NSWindow ,un NSTextField et un NSView par le bias de ma seule et unique classe view.c (qui hérite de NSView). C'est vrai, il faudrait que je vire l'objet View dans IB. Seulement, si je vire l'objet View de IB, je n'ai pas ma fenêtre qui s'affiche lorsque je lance l'application. Quoi ajouter au code ?

    Donc forcément, il rajoute une NSView "standard", celle d'Apple qui ne fait rien côté dessin. Et non pas une instance de ta classe "view"...
    C'est p'tet plutôt "self" que tu devrais mettre à  la place de ton objet "view" du coup, non ? (et virer la déclaration de "NSView* view = ..." plus haut) ?

    C'est juste. (par contre self ne fonctionne pas.)
    Je me suis trompé,c'est pas une simple NSView que je veux afficher mais une vue (View) contenant un rectangle vert (cf drawrect:) Peut-être dois créer une deuxième sous-classe de NSView qui affichera mon carré vert ?

    Voici le "projet" si jamais :
    Télécharger le "projet"
  • CrazyJoCrazyJo Membre
    21:48 modifié #6
    Enfait je sais comment afficher une sous-vue personnalisée de NSView en glissant-déposant d'abord une nsview dans une nswindow puis en changeant sa classe avec l'inspecteur. Je souhaite faire les mêmes étapes et arriver au même résultat mais par le bias du code pur et dur.
  • AliGatorAliGator Membre, Modérateur
    21:48 modifié #7
    dans 1252948563:
    Peut-être dois créer une deuxième sous-classe de NSView qui affichera mon carré vert ?
    Ah ben dans ce cas, oui.

    Il te faut bien éclaircir ce que tu veux.

    1) Tu veux créer une fenêtre, contenant elle-même un NSTextField et une NSView sachantdessinant un rectangle.

    2) Donc déjà , il te faut une sous-classe de NSView, "GreenRectView", qui sache dessiner un rectangle vert.

    3) Puis il faut que quelque part dans ton code tu fasses les étapes de construction de ton interface : création de la NSWindow, du NSTextField et de ta GreenRectView, puis placer le NSTextField et la GreenRectView en tant que subview dans cette NSWindow (tu auras pris soin de mettre la frame que tu veux à  la création de ton NSTextField et GreenRectView pour que ça soit positionné comme il faut dans la NSWindow qui sera leur superview), puis demander à  la window "makeKeyAndOrderFront" pour la faire passer au premier plan.

    Le problème c'est que tu as mélangé l'étape 2 et 3, tu as tout mis un peu au même endroit.
    Il te faut une classe GreenRectView (enfin ta classe "View" actuelle, si tu veux) avec dedans juste le code "drawRect" pour l'étape 2... et tout le code que tu as dans ton awakeFromNib, qui correspond à  l'étape 3, il faut le mettre autre part.

    Car awakeFromNib est appelé quand un objet de la classe où il est codé est extrait d'un NIB... or ici tu l'as mis dans view.h : tu as surchargé le awakeFromNib de la classe View, donc ça ne sera appelé que si ton objet View est créé à  partir d'un NIB... Et comme le code a pour effet lui-même de créer une NSView (même pas une View d'ailleurs), bah tu te mélanges les pinceaux.
    Il faut donc réaliser l'étape 3, de création de ton interface, autre part que dans awakeFromNib de View.h. Faut pas tout mélanger n'importe comment non plus ;)


    Pour cela le plus simple est de te créer un "AppController" : c'est à  un dire que dans ton MainMenu.nib, tu crées un nouvel NSObject, puis tu changes sa classe en "MyAppController" par exemple, puis demande de créer les fichiers ("Write Files...") pour cet objet (ou sinon depuis Xcode tu demandes de créer une nouvelle classe dérivant de NSObject que tu appelles MyAppController).
    Du coup quand le MainMenu.nib va se charger, ton objet MyAppController va être créé, et son but sera de contrôler l'application... Et dans ce cas tu pourras mettre ton code de awakeFromNib dans MyAppController.m (et non plus dans View.m où il n'a plus lieu d'être puisque ta View n'est pas créée par NIB donc awakeFromNib ne sera plus appelé).

    Et bien sûr en plus il faut modifier ton code de awakeFromNib pour non plus créer une bête NSView mais du coup une View (ou une GreenRectView, si jamais tu l'as renommée)

    Il y a potentiellement d'autres endroits pour appeler tes lignes de code de l'étape 3 que tu as mises dans ton awakeFromNib, genre le délégué de l'application, etc... mais bon, le AppController reste le plus simple (et le plus classique)... sauf dans le cas particulier (et étrange) ou tu voudrais ne plus avoir un seul NIB, même plus MainMenu.nib, même s'il est presque vide.
  • CrazyJoCrazyJo Membre
    21:48 modifié #8
    o:) pour ta réponse clair et concise ! Il me semble que tout soit clair pour moi maintenant.

    Hier soir j'avais trouvé la solution à  mon problème peu avant ta réponse grâce à  cette page web : http://www.nongnu.org/gstutorial/en/ch10.html. Du coup, voici mon projet xCode contenant :

    - 2 classes (Controller et Graph)
    - Je n'ai pas touché à  IB. Tout ce passe dans les classes et le fichier main.m
    - Utilisation des delegates en lieu et place du awakeFromNib:
    - Pas de création d'une NSView mais de la sous-classe de NSView nommée Graph avec une seule fonction : drawRect:

    Télécharger le projet
Connectez-vous ou Inscrivez-vous pour répondre.