Hiérarchie de vue

UniXUniX Membre
15:22 modifié dans API AppKit #1
Salut.

Voilà , j'ai une vue perso que j'affiche dans une NSScrollView. Maintenant, je voudrais pouvoir afficher une image en haut de ma vue, c'est à  dire avoir une image positionnée par exemple à  50 du bord gauche et 50 du haut, mais lorsque je bouge avec mes scrollers, elle ne doit pas bouger de place .... Je sais pas si je suis clair, c'est comme une incrustation sur une vidéo ....

Cette image je la construis dans une NSView perso. Je me dis donc, il suffit de la rendre subview de la NSScrollView, et le tour est joué. Mais non, car elle s'éfface dès que je bouge mes scrollers ....

Quelle est la bonne démarche à  suivre ...?

Réponses

  • 15:22 modifié #2
    Les subviews de la scrollview sont:
    -2 NSScroller
    -1 NSClipView (dont la subview est le document)
    - éventuellement des NSRulerView.

    Pour disposer les subviews dans la scrollview, il faut surcharger la méthode -tile.

    Donc dans ton cas, tu rajoutes ta vue dans les subview de la scrollview et définit son frame dans la méthode -tile (n'oublie pas le [super tile]; ).
  • AliGatorAliGator Membre, Modérateur
    15:22 modifié #3
    Et on peut pas la mettre par dessus la scrollView, mais sans pour autant que ce soit une subView de la scrollView ?

    (Genre on la met en dehors et ensuite un utilises les flèches pour déplacer la vue ?)
  • UniXUniX Membre
    15:22 modifié #4
    C'est en fait la question que je suis en train de me poser, après avoir rapidos lu la doc sur la méthode-tile .....
  • 15:22 modifié #5
    Un peu RTFM ta question Ali, on peut redéfinir la clipview avec la méthode -setContentView:. C'est donc visiblement possible.
  • UniXUniX Membre
    15:22 modifié #6
    Bon, je viens d'essayer de "poser" tout simplement une vue perso sur la NSScrollView dans IB, mais c'est pas mieux, elle disparaà®t dès que je bouge un scroller ....

    Bon, il va donc falloir que je regarde cette méthode -tile .....
  • UniXUniX Membre
    15:22 modifié #7
    Quelqu'un a déjà  fait ça ?

    Parceque la doc de la méthode tile: n'est pas vraiment très explicite ..... :(
  • 15:22 modifié #8
    C'est pas plus compliqué que ça:
    [tt]-(void)tile {
    [super tile];
    NSRect r;
    //le calcul pour définir le frame de ton imgae
    [uneImageView setFrame:r];
    }[/tt]
  • UniXUniX Membre
    novembre 2005 modifié #9
    Bon, ça me fait pas grand chose ..... J'ai du oublier un truc quelquepart ...... Voici mon code :

    La sous-classe de NSSCrollView :
    @implementation JCScrollView<br /><br />- (void)tile<br />{<br />	[super tile];<br />	id controlleur = [[NSApplication sharedApplication] delegate];<br />	NSRect frameVueParent = [self bounds];<br />	NSRect frameAfficheurs = NSMakeRect(20,(frameVueParent.size.height - 54),78,34);<br />	[[controlleur vueAfficheurs] setFrame:frameAfficheurs];<br />}<br /><br />@end
    


    et vueAfficheurs est une variable d'instance de mon controlleur initialisée comme ceci :
    VueAfficheurs *vue = [[VueAfficheurs alloc]init];<br />[self setVueAfficheurs:vue];
    


    Et dans IB, j'ai bien entendu mis ma classe JCScrollView comme classe perso de la scroll view.
  • 15:22 modifié #10
    Une vue ne s'initialise pas avec init, mais avec initWithFrame:.
  • UniXUniX Membre
    novembre 2005 modifié #11
    Bon, j'ai corrigé ma classe controlleur :
    NSRect frameVueParent = [[[vueCarte superview]superview]frame];<br />NSRect frameAfficheurs = NSMakeRect(20,(frameVueParent.size.height - 54),78,34);<br />VueAfficheurs *vue = [[VueAfficheurs alloc]initWithFrame:frameAfficheurs];<br />[self setVueAfficheurs:vue];
    


    Mais pas mieux .... j'ai toujours rien qui s'affiche.
  • novembre 2005 modifié #12
    Est-ce que tu as seulement fait quelque part [myScrollView addSubview:view];

    N'initialise pas de vue dans le tile. ça sert juste à  diposer les subviews de la scrollview, ce qui implique qu'elles existent préalablement.

    Et accessoirement ta vue doit être une variable d'instance de la scrollview. Aller chercher des valeurs 'à  l'extérieur' comme tu le fais, ça ne se fait pas.

    Donc:
    1. Tu définis une vue afficheur comme variable d'instance;
    2. Tu rajoutes des méthodes pour permettre à  ton contrôleur de modifier les valeurs de la vue et y accéder;
    3. Tu surcharges initWithFrame et tu y initialises là  (et pas ailleurs) cette sous-vue, tu la rajoutes dans les subviews;
    4. Tu la releases ds le dealloc, que tu surcharges également;
    5. Tu surcharges le tile.
  • UniXUniX Membre
    15:22 modifié #13
    Bon, j'ai suivi ta méthode pas à  pas.

    Voici ma classe :
    - (id)initWithFrame:(NSRect)frame <br />{<br />&nbsp; &nbsp; self = [super initWithFrame:frame];<br />&nbsp; &nbsp; if (self) <br />	{<br />		NSRect boundsVueParent = [self bounds];<br />		NSRect frameAfficheurs = NSMakeRect(20,(boundsVueParent.size.height - 54),78,34);<br />		VueAfficheurs *vue = [[VueAfficheurs alloc]initWithFrame:frameAfficheurs];<br />		[self setVueAfficheurs:vue];<br />		[self addSubview:vueAfficheurs];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return self;<br />}<br /><br />- (id) vueAfficheurs<br />{<br />&nbsp; &nbsp; return vueAfficheurs;<br />}<br /><br />- (void)setVueAfficheurs:(VueAfficheurs *)vue<br />{<br />	[vue retain];<br />	[vueAfficheurs release];<br />	vueAfficheurs = vue;<br />}<br /><br />- (void)tile<br />{<br />	[super tile];<br />	NSRect boundsVueParent = [self bounds];<br />	NSRect frameAfficheurs = NSMakeRect(20,(boundsVueParent.size.height - 54),78,34);<br />	[vueAfficheurs setFrame:frameAfficheurs];<br />}
    


    Alors, plusieurs soucis.
    1) l'appli ne passe pas par la méthode initWithFrame: de cette classe. J'ai donc mis le code contenu dans la méthode ailleurs pour faire les essais.

    2) maintenant, j'ai ma vue qui s'affiche au dessus de la scroll view, mais dès que je bouge un scroller ou que je zoome, elle disparaà®t.

    Bon, petiti à  petit on avance ....  ;)
  • novembre 2005 modifié #14
    Sorry, pour la scrollview c'est initWithCoder qu'il faut surcharger.

    à‰ventuellement, utilise:
    [self addSubview:vueAfficheurs positioned:NSWindowAbove relativeTo:[self documentView]];
  • UniXUniX Membre
    15:22 modifié #15
    Bon, j'ai pas essayer de changer initWithFrame par initWithCoder, mais j'ai modifié addSubview comme tu m'as indiqué, et c'est pareil, la vue s'affiche puis s'efface dès que je bouge ....

    Il faut demander à  redessiner la vue ? Parceque quand je mets la fenetre dans le dock et que je ressors, hop elle est de nouveau là  ....
  • 15:22 modifié #16
    Essaie needsDisplay à  la fin du tile.
  • BruBru Membre
    15:22 modifié #17
    Les gars,

    Vous avez oublié la règle d'or : on ne peut (doit) pas empiler des NSViews de même niveau.
    Donc 2 views qui sont soeurs ne doivent absolument pas se chevaucher.
    En effet, il y en aura toujours une qui recouvra l'autre quand son drawRect: sera appellé.
    De plus, l'ordre d'appel des drawRect: est complètement aléatoire, en fonction des demandes de mise à  jour par le système. Dans ton cas, à  l'initialisation, il semble bien que le dernier drawRect: appelé est celui de ton "Afficheur". Mais quand tu scrolles, c'est la NSClipView qui est mise à  jour, et donc, c'est son drawRect: qui est utilisé, recouvrant ainsi ton "Afficheur".

    Dans le code de Unix, les 2 soeurs sont sa vue "Afficheur" et la NSClipview.

    La méthode tile sert justement à  modifier les frames de chaque soeurs afin qu'elles ne se chevauchent pas. Ce qui n'est pas fait dans l'implémentation de cette méthode par Unix.

    Moi, j'aimerai savoir ce que veut faire (visuellement parlant) Unix. Car il y a peut-être d'autres solutions plus simples.
    Eventuellement, fais nous un petit montage genre screenshot pour qu'on voit vraiment ce que tu veux.

    .
  • UniXUniX Membre
    15:22 modifié #18
    Bon, voilà  2 belles images alors. Sur les images, on voit la NSScrollView (ou sa dérivée) qui affiche une belle image. J'ai représenté en rouge la vue vueAfficheurs.
    Effectivement comme l'a dit Bru, les 2 vues se chevauchent.

    Sur l'image 2, on voit le scroller horizontal qui est décalé vers la droite, pour afficher la partie droite de l'image. Mais la vueAfficheurs, elle, n'a pas bougé.

    C'est ce que je veux obtenir.

    scrollview1.jpg

    scrollview2.jpg
  • BruBru Membre
    15:22 modifié #19
    Le plus simple pour toi est donc d'utiliser une child window.

    Une child window est une fenêtre qui est attachée à  une fenêtre mère (en l'occurence, celle qui contient le srcollView).

    .
  • UniXUniX Membre
    15:22 modifié #20
    OK je vais regarder ça, mais comme ça sans rien avoir regardé, il me vient une question à  l'esprit : il est possible d'avoir une fenêtre sans barre de titre, et sans bords ?
  • fouffouf Membre
    15:22 modifié #21
    Oui aves le NSBorderlessWindowMask et avec initWithMask: (ou un truc dans ce genre la). ;)
  • BruBru Membre
    15:22 modifié #22
    Voici en gros les étapes que tu devras faire (à  l'initialisation de la fenêtre de la scrollView, ou dans le awakeFromNib du contrôleur de la fenêtre) :

    1. dans IB, création d'une custom view pour y mettre les éléments que tu veux, avec l'outlet qui va bien.

    2. dans Xcode, création d'une fenêtre sans bordure :
    [tt]NSWindow *wnd=[[NSWindow alloc] initWithContentRect:[customView bounds] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];[/tt]

    3. utilisation de la custom view comme content-view de cette fenêtre :
    [tt][wnd setContentView:customView];[/tt]

    4. ajout de cette fenêtre comme child-window:
    [tt][[tableView window] addChildWindow:wnd ordered:NSWindowAbove];[/tt]

    5. affichage de la fenêtre
    [tt][wnd orderFrontRegardless];[/tt]

    Le plus dur est de déterminer les coords de la child window pour qu'elle soit au dessus de la scrollView.

    .
  • UniXUniX Membre
    15:22 modifié #23
    <3 <br />
    Coool ! J'ai réussi à  obtenir ce que je voulais : un grand merci Renaud et Bru !

    2 petites dernières précisions :
    - ma scrollview se trouve en fait sur un onglet de NSTabView, et bien entendu, je ne souhaite voir la child window que lorsque le bon onglet est affiché, quelle est la méthode la plus appropriée pour masquer/afficher cette child windows ?

    - si au lieu d'avoir une image dans ma vue vueAfficheurs, j'ai un NSBezierPath, est-il possible de rendre le fond de la vue (et de la child window ?) transparent (pour voir à  travers la vue partout ou je n'ai pas dessiné avec le bezier) ?
  • Eddy58Eddy58 Membre
    novembre 2005 modifié #24
    - Pour rendre ta vue transparente, il faut surcharger sa méthode isOpaque. :)
    - Pour cacher ta fenêtre tu fais un simple orderOut: dessus et un orderFrontRegardless pour la montrer.
  • UniXUniX Membre
    15:22 modifié #25
    Ben je pensais que orderOut n'allait pas fonctionner sur une child window (vu qu'elle est "accrochée" à  sa fenêtre parent) ..... et j'avais raison !
    Pour contourner le problème, lorsque l'onglet change pour afficher la vue parent, je positionne la fenêtre child, je la rend child de sa parent, et je la montre. A l'inverse, lorsque l'onglet rechange, je la "déchild" puis je la cache.

    C'est cool. Merci à  tous. Vive Objective-Cocoa  :p
  • BruBru Membre
    15:22 modifié #26
    dans 1132736627:

    Ben je pensais que orderOut n'allait pas fonctionner sur une child window (vu qu'elle est "accrochée" à  sa fenêtre parent) ..... et j'avais raison !


    C'est étrange ce que tu dis là ...
    orderOut fonctionne chez moi pour les child windows...

    .
  • UniXUniX Membre
    15:22 modifié #27
    Ben je viens de vérifier, moi ça ne fonctionne pas .....
    La fenêtre principale disparaà®t un bref instant et réapparaà®t, mais la child est toujours là  .....

  • UniXUniX Membre
    15:22 modifié #28
    Concernant les vues transparentes, j'ai surchargé isOpaque: de NSView pour retourner YES, ça c'est OK, mais ma fenêtre child window, elle, n'est pas transparente .....
    Pourtant, lors de son initialisation, j'ai bien fait un [maFenetre setOpaque:NO] ...
  • fouffouf Membre
    15:22 modifié #29
    Il ne faut pas que tu oublies de faire un setAlphaValue: Par contre, ca risque aussi de rendre ta vue transparente. Faut essayer
  • UniXUniX Membre
    15:22 modifié #30
    Non, comme tu l'as dit, tout est devenu transparent, mais j'ai fait :
    [maFenetre setBackgroundColor:[NSColor clearColor]]
    

    et là  ça fonctionne.
Connectez-vous ou Inscrivez-vous pour répondre.