NSScrollView et NSTableView

20:05 modifié dans API AppKit #1
Hello,

Il y a un truc qui m'échappe avec NSTableView: la vue quand est inclue dans une NSScrollView dans IB, alors que dans les faits la scrollview semble subordonnée à  la tableview, dans la mesure où les entêtes des colonnes ne bougent pas quand on bouge les scrollers, alors que si la table aurait été "bêtement" subordonnée à  la scrollview, les entêtes auraient du bouger lorqu'on défile verticalement.

Quelqu'un a une idée pour reproduire ce genre de comportement?

Réponses

  • BruBru Membre
    20:05 modifié #2
    Une scrollview n'est pas la vue qui fait défiler les infos. En fait, elle est composée de plusieurs autres views, dont les NSScrollers, les NSHeaderViews et NSCornerViews (dans le cadre d'une tableview) et enfin d'une NSClipView.

    C'est la NSClipView qui contient la vue (dans ton cas la NSTableView) qui doit être défilée en fonction de la position des ascenseurs.

    Schématiquement, ça done ça :


    [Fichier joint supprimé par l'administrateur]
  • ClicCoolClicCool Membre
    20:05 modifié #3
    Ah oui c'est encore plus clair avec ton shéma :)

    C'est pour ça que tu m'avais conseillé de ne pas me contenter d'un [tableView setNeedsDisplay:YES] mais plutot d'utiliser [[[tableview superview] superview] setNeedsDisplay:YES] pour forcer la scrollView entière à  se redessiner y compris les headers de mes colonnes. ;)
  • ClicCoolClicCool Membre
    20:05 modifié #4
    Et, pour en revenir à  ce qui préoccupait Renaud, il est donc possible d'inclure dans une scrollView des éléments insensibles au scroll en plus d'une vue répondant au scroll ?

    Par exemple une vue latérale d'entêtes et, à  côté, une vue de lignes et colonnes scrolable pour reproduire une "tableView inversée" ? (entêtes latérales et scroll horizontal pour faire défiler dans les colonnes les éléments d'un NSArray)

    Ce serait dur à  faire ? ???
    Faudrait repartir de zéro ou serait-il possible de sousClasser tableView ?
  • 20:05 modifié #5
    Merci pour les réponses.

    Ton exemple résume ce que je dois faire, si je l'ai bien compris: la première colonne doit toujours être visible (donc sensible au scroller vertical mais pas au scroller horizontal).

    Dans Keynote (pour la table qui sert à  l'entrée des donnes des graphiques), ils sont sous classé la scrollview, donc je suis parti dans cette direction aussi.
  • ClicCoolClicCool Membre
    20:05 modifié #6
    Bon courrage et tiens nous au courant Renaud ;)
  • 20:05 modifié #7
    Je suis d'humeur altruiste, tous mes contrôles persos sont dans un framework qui sera légué à  OC pour enrichir la section ressources ;)
  • ClicCoolClicCool Membre
    20:05 modifié #8
    dans 1104849026:

    Je suis d'humeur altruiste, tous mes contrôles persos sont dans un framework qui sera légué à  OC pour enrichir la section ressources ;)

    <3 <br />ça m'étonne pas de toi mais c'est pas une raison pour pas te dire [size=10pt]merci[/size]  :o

    Par ailleurs, j'ai jetté un oeil sous IB (en basculant l'affichage en mode liste) et je suis surpris, après ce que nous a expliqué Bru, de voir qu' IB ne nous révèle, comme contenu de la ScrollView, que la tableView contenant ses tableColonnes ?
    Pas de trace, dans la hierarchie, de NSCornerView, NSHeaderView ni de NSClipView  ???
  • BruBru Membre
    20:05 modifié #9
    dans 1104852409:

    Par ailleurs, j'ai jetté un oeil sous IB (en basculant l'affichage en mode liste) et je suis surpris, après ce que nous a expliqué Bru, de voir qu' IB ne nous révèle, comme contenu de la ScrollView, que la tableView contenant ses tableColonnes ?
    Pas de trace, dans la hierarchie, de NSCornerView, NSHeaderView ni de NSClipView ???


    En fait, j'ai un peu simplifié les headersViews. Comme elles doivent défiler dans le sens horizontal, elles sont elles aussi incluses dans une NSClipView (qui ne peut que défiler horizontalement).

    Pour IB, je ne sais pas trop comment il interprète les choses. Pour la cornerView, elle est accessible en reliant la tableView à  une NSView déposée dans les instances de mainMenu.nib, puis en connectant au pseudo outlet "cornerView"

    .
  • ClicCoolClicCool Membre
    20:05 modifié #10
    dans 1104866266:

    En fait, j'ai un peu simplifié les headersViews. Comme elles doivent défiler dans le sens horizontal, elles sont elles aussi incluses dans une NSClipView (qui ne peut que défiler horizontalement).


    Merci Bru,

    J'avais complètement zappé l'existence des NSClipView.
    Il s'agirait donc, pour les header, d'être inclus dans une NSClipView qui ignore les appels de scroll vertical mais réponds à  ceux du scroll horizontal ?

    J'en était resté à  Power plant où, si mes souvenirs sont bons, n'importe quelle vue pouvait être amenée à  répondre aux appel d'un scroll pourvu qu'elle soit une "sub-view" du srcoll et ait implémenté les méthodes appropriées. (il me semble qu'un multiple héritage était nécessaire ici ...)

    Donc Renaud "n'a plus qu'à  faire une NSClipView qui répond au scrol vertical pour ses "header latéraux" ?

    N'empèche que comme toi je me demande quelle cuisine fait I.B. pour ne pas afficher l'existence des clipView ???
    Sans doutes ne sont elles crées et instanciée que dans le run-time ?
    ça aurait été cool qu'elles figurent sous I.B. et permettent de choisir si les header sont latéraux et sensibles aux scroll vertical etc.. ce qui permettrait des tableView inversées qui manquent terriblement à  cocoa.
    Heureusement qu'il y'a Renaud qui s'y colle pour combler ce manque flagrant  :o

    Ceci dit Renaud, vérifie que XCode 2 ne corrige pas ce manque dans quelques mois avec l'arrivée de Tiger avant de te retrouver avec aussi peu de cheuveux que l'avatard de Tiff ;) (Salut Tiff :) )


  • janvier 2005 modifié #11
    Cette vue a en fait un fonctionnement différent de la NSTableView, dans la mesure où son comportement est plus proche d'une vue excel (le nombre de lignes et de colonnes est indéterminé, et l'ascenceur est fonction du contenu et non de la taille de la vue, vu qu'elle est susceptible de s'agrandire même si aucun contenu n'est rajouté). Et ça, je doute que Tiger l'intègre ;) Et puis, tu sais à  quel point je tiens à  la compatibilité GNUStep ;).
  • BruBru Membre
    20:05 modifié #12
    Pour vous mettre d'accord tous les 2 :

    Ce que tu veux faire Renaud sera difficile...

    La seule solution la plus facile à  mon avis est de créer une NSClipView "collée" (donc incluse la NSWindow/NSView qui contient ta tableView) à  la scrollView, et qui reçoit les notifications de modification NSViewBoundsDidChangeNotification de la NSTableView afin de maintenir la synchronisation du déplacement vertical de la liste.

    La solution complexe (mais peut être plus propre) est de sous-clasisser NSTableView.

    .
  • janvier 2005 modifié #13
    J'ai peut être un autre solution la plus facile :P. Le nombre de lignes affichées (et donc la taille du tableau est fonction de trois critères: la taille du clipview, la taille de la table (dans certains cas uniquiment), le nombre de lignes minimum que doit contenir la table (fournie par un datasource) et la position de la sélection. La plus grande de ces valeurs est reprise pour déterminer la taille de la table (à  quelques exceptions près). Par défaut, la table contient par exemple 30% de lignes en plus que ce que peut afficher la table. Le fait de pousser sur les flèches des scrollers quand on est au plus bas augmente l'indice de la sélection de 1, et donc la taille du tableau. Le fait de pousser sur Page Down augmentent l'indice de la sélection d'un nombre de lignes égal au nombre de lignes affichées dans la clipview-1,... Voilà  pour le principe.

    Quand à  sous classer NSTableView, j'y ai pensé, mais je me dis que ça n'a pas été fait chez Apple (pour Keynote), c'est qu'il est plus simple de refaire from scratch.  OK, il y a des imbéciles partout (en particulier chez Apple pour l'optimisation des iApps), mais bon... :P
  • BruBru Membre
    20:05 modifié #14
    Yes !

    J'ai réussi à  créer cette fameuse entête de ligne pour une NSTableView (comme dans Excel)...

    Voici comment j'ai procédé :

    1. dans IB, j'ai mis une custom view à  gauche de ma tableView. Dans les infos, j'ai mis "custom class" à  NSClipView. Je l'ai enfin reliée à  un outlet qui va bien.

    2. Dans le awakeFromNib de mon contrôleur, j'ai crée une NSCell prototype (pour contenir le texte de l'entête de chaque ligne).

    3. Ensuite, j'ai créé une NSMatrix de largeur identique à  celle de ma custom clip view, et de hauteur identique à  celle de la tableView. Le nombre de cellulle est 1 en horizontal, et pour le vertical, c'est le nombre retourné par la méthode numberOfRowsInTableView: de ma tableView. J'ai mis le cellSize de la matrix à  celle en hauteur d'une ligne de la tableView, et en largeur à  celle de la custom clip view. Enfin le intercellSpacing est directement mis de la tableView vers la custom clip view.

    3. Après, grâce à  la notification NSViewBoundsDidChangeNotification de la NSClipView qui englobe la tableView, je synchronise le déplacement vertical de ma custom clip view avec celui des lignes de la tableView.

    Voilà , y'a finalement pas trop de code, et ça marche impec.

    .
  • ClicCoolClicCool Membre
    20:05 modifié #15
    Tu bosses encore un jour comme aujourd'hui ?

    En tous cas bravo.

    sinon, on peut voir ta merveille ?
  • BruBru Membre
    20:05 modifié #16
    dans 1104969542:

    sinon, on peut voir ta merveille ?


    Il faut que je nettoie un peu le code, sinon je vous poste ça ce soir.

    .
  • ClicCoolClicCool Membre
    20:05 modifié #17
    :o
  • janvier 2005 modifié #18
    Bon, vous avez demandé à  être tenu au courant, alors maintenant faut assumer ;)

    Bon j'al choisi l'optique de refaire un vue à  part entière, parce que 1. il y avait plusieurs choses dont j'avais besoin non repris dans NSTableView, et je préfère dans ce cas parfois partir de 0 que me battre avec un truc que je ne maà®trise pas 2. ça m'amuse.

    Bon alors les particularités principales de cette table sont 1. les vues d'en-tête de colonne sont elles mêmes des tables, et donc bénéficient des possibilités de celles-ci en temps normal, le datasource de ces tables est géré par la table principale mais si on veut vraiment personnaliser c'est possible 2. on peut fusionner des cellules, 3. on peut choisir le sens de remplissage (vertical ou horizontal).

    Je dois encore ajouter le drag&drop, le copier coller, et des options pour mieux personnaliser ça.

    Alors quelques screenshots:

    [Fichier joint supprimé par l'administrateur]
  • cbrandtcbrandt Membre
    20:05 modifié #19
    beau travail ! o:)
  • BaardeBaarde Membre
    20:05 modifié #20
    Impressionnant...
  • muqaddarmuqaddar Administrateur
    20:05 modifié #21
    Bravo Renaud !
    Je retourne à  mes études...
  • fouffouf Membre
    20:05 modifié #22
    Ca m'interresse. Ou on peut recuperer le code ?

    Sinon, ca a l'air d'être super. Bravo :adios!: o:)
  • 20:05 modifié #23
    Thanks,

    Bien entendu, comme c'est marqué plus haut le code est mis dans un framework, qui sera rendu public sous la licence LGPL (donc le code source sera dispo, et utilisable dans des softs payants pour peu qu'on en mentionne l'origine). Laissez moi juste finir mes examens que je paufine ça à  mon aise ;)

    Par contre ClicCool pour les bindings ça risque de ne pas être évident: chaque cellule est identifiée par deux numéros, et non la colonne et le numéro de ligne, dans je vois mal comment inégrer ça dans un KVM, à  moins que tu n'ais une bonne idée.
  • ClicCoolClicCool Membre
    20:05 modifié #24
    Bravo Renaud ça a l'air splendide !
    Merci
    Quand on sait que tes exams ont commencé Lundi !!!

    dans 1105699514:

    Par contre ClicCool pour les bindings ça risque de ne pas être évident: chaque cellule est identifiée par deux numéros, et non la colonne et le numéro de ligne, dans je vois mal comment inégrer ça dans un KVM, à  moins que tu n'ais une bonne idée.


    Les cellules sont numérotées de 1 (ou 0) à  n ? sans trou ?
    Genre pour colonnes :
    1  2  3  4
    5  6  7  8
    et pour 2 colonnes :
    1  2
    3  4
    5  6
    7  8
  • janvier 2005 modifié #25
    Non non
    Pour un table orientée verticalement
    [tt]
    (0,0) (1,0) (2,0)
    (0,1) (1,1) (2,1)
    (0,2) (1,2) (2,2)
    [/tt]

    Le piège aussi est qu'on peut demander à  avoir un nombre indéterminé de cellules (toujours moyen d'aller plus bas, la taille de la table n'étant pas déterminée par le datasource), donc le datasource est susceptible de recevoir un message demandant d'éditer la cellulle (6,7) alors que la table est vide.

    Et si à  ça on rajoute la fusion des cellules. Je pense pas qu'il faille penser à  ça dans les bindings. ça se fait en fait avec une méthode de délégué qui renvoie un NSRect. L'origine du Rect étant la position de la cellule placée en argument dans la zone fusionnée, et la taille étant la zone fusionnée.

    Est-ce que les bindings permettront aussi de modifier le type de cellule utilisée en fonction du contenu?
  • ClicCoolClicCool Membre
    20:05 modifié #26
    dans 1105709085:

    Est-ce que les bindings permettront aussi de modifier le type de cellule utilisée en fonction du contenu?


    ça dépend du temps de refroidissement du fut du canon ;D

    Est-ce que les cellules de ton tableau existent réellent ?
    ou celà  fonctionne-t-il un peu comme dans les tableView avec une cellule d'édition unique pour chaque colonne ?
    De quelle façon est déterminé la nature des donnée ?  Est -elle explicite, dans une propriété (ou pseudo-propriété) du data source ?
    Ou est-ce ta table qui teste les objets renvoyés ?

    etc ...

    P.S. faudraot qu'in en doscute p-e ?
  • janvier 2005 modifié #27
    Non les cellules n'existent pas. À la base c'est une cellule unique pour la table (et non les colonnes) et une pour les entêtes, mais le délégué est interrogé à  chaque fois pour savoir si un autre type de cellule n'est pas requis. Les données sont bêtement renvoyées par le datasource. Les titres des entêtes s'obtiennent également par le datasource (ou par un datasource si on décide qu'ils ne dépendent pas du datasource principal).
Connectez-vous ou Inscrivez-vous pour répondre.