IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Discussion :

Glisser-déposer entre deux QTreeView

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut Glisser-déposer entre deux QTreeView
    Bonsoir,

    je cherche à réaliser un glisser-déposer d'une QTreeView à une autre QTreeView. J'ai suivi un tutoriel pour apprendre à gérer le drag & drop dans une même liste (ou internal move) mais je ne sais pas vraiment comment m'y prendre lorsqu'il s'agit de :

    - Cliquer sur une ligne du premier QTreeView (standardItem qui a été créé avec un QString en paramètre et qui a ensuite été ajouté au model via un appendRow())

    - Maintenir le clic et déplacer la souris sur le deuxième QTreeView

    - Relâcher la souris et déposer l'item avec le même nom dans ce dernier

    Aussi, l'élément n'est pas vraiment glissé-déposé puisque, de préférence, j'aimerais qu'il se copie et qu'il soit donc toujours présent dans le QTreeView initial.

    Pourriez-vous me donner des pistes ? Je reconnais qu'il y a beaucoup de posts sur la technique de drag&drop mais il y en a tellement que je m'y perds :s

    Merci beaucoup !

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut
    Bonjour,

    je me permets de répondre puisque j'ai bien avancé sur le sujet et que mes questions ne sont plus les mêmes.

    Pour réaliser un "drag & drop" d'un QTreeView à un autre, je me suis inspiré du code ci-joint issu d'un exemple Qt.

    Cependant, dans ce code, je ne comprends pas bien comment est géré le LIEN entre la QStrinList membre du QStringItemModel et donc ce dernier.

    On dirait qu'il apparaît implicitement dans la méthode setData() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        bool setData(const QModelIndex &index,
                     const QVariant &value,
                     int role = Qt::EditRole )
        {
            Q_UNUSED( role );
     
            if (index.isValid()) {
                _list.replace(index.row(), value.toString());
                emit dataChanged(index, index);
                return true;
            }
            return false;
        }
    En fait, je pense que le concept de index de model est encore flou pour moi. Dans setData(), il semblerait que l'on remplace déjà à l'index donné la valeur par celle en entrée. Donc la liste est bien changée.

    Et j'imagine que c'est le signal dataChanged(index, index) qui permet d'afficher la nouvelle liste du model dans la vue ? Si c'est le cas, je ne comprends pas comment le signal procède pour faire le lien entre le modèle et la QStringList membre sachant qu'il ne la connait pas initialement. (D'ailleurs, pourrait-on par exemple refaire le même procédé avec une liste différente d'une QStringList (par exemple QList de structures) tout en gardant ce rafraichissement à l'affichage après un setData() ?)

    J'espère que vous pourrez me débloquer un peu.

    Merci beaucoup !
    Fichiers attachés Fichiers attachés

  3. #3
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    Tout d'abord, la bible du modèle-vue de Qt : http://qt-project.org/doc/qt-4.8/mod...ogramming.html

    C'est plus simple que ça en a l'air. Tout modèle hérite de QAbstractItemModel. Toute vue hérite de QAbstractItemView. En fait les mécanisme de rafraichissement de la vue, etc., se trouvent dans les implémentations de ces classes. Quant au dessin, il est assuré par un délégué, héritant de QAbstractItemDelegate : la vue demande au délégué de peindre une zone visible (de l'index tant à l'index tant), et le délégué interroge le modèle pour récupérer les données à dessiner.

    Par exemple, dans qabstractitemview.cpp, si tu regardes à setModel(), tu vois que dataChanged() du modèle est connecté à un slot du même nom. Si tu regardes le code du slot, tu vois bien l'update() et donc tu comprends pourquoi cela provoque un rafraichissement.

    Donc un modèle, c'est une interface à utiliser pour afficher des données dans une vue sans se casser la tête vu que le mécanisme est déjà fait. Le modèle sert donc d'accesseur à la donnée. Ses méthodes d'accès, data() et setData(), sont à redéfinir pour travailler sur un type de donnée personnalisé, mais certaines classes courantes existent déjà (il y a par exemple une classe QStringListModel officielle, même si l'exemple permet de comprendre plus facilement).

    Concernant les index, chaque élément d'un modèle est indexé (ligne/colonne, dans le cas d'une simple liste on ne s'occupe pas de la colonne). L'indexation peut être gérée aussi par le développeur en redéfinissant la méthode index() et en appelant createIndex(), bon là c'est le niveau au-dessus. Là, l'index.row() correspond simplement à la place d'un élément dans la QStringList, et donc à l'affichage, si aucun tri n'est fait.

    Pour utiliser avec ton propre enum, il n'y a deux difficultés :
    - on travaille avec des QVariant. Il faut que ton enum devienne un QVariant. Dans setData(), bien sûr ce n'est pas toString() qu'il faut utiliser vu que ta donnée n'est pas une QString mais ton enum. Et pour ceci je te renvoie à la doc : http://qt-project.org/doc/qt-4.8/qme...CLARE_METATYPE
    - l'affichage. C'est le délégué (delegate) qui est chargé d'afficher chaque élément d'un modèle dans une vue, c'est dedans qu'il y a vraiment la méthode paint() qui détaille le dessin d'un item. Le delegate par défaut doit s'attendre à ce que data() renvoie un QString, donc il fait toString() et il dessine le texte. Tu as besoin de faire ton propre delegate, qui sâche traiter le QVariant renvoyé par data() si ce n'est plus un QString.

    Bonne lecture, n'hésite pas si tu as encore des questions

  4. #4
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    Salut Troudhyl et merci beaucoup pour ton aide

    Alors j'ai avancé un peu depuis hier et ton explication clarifie encore les choses!

    Actuellement, j'ai deux modèles qui héritent de QAbstractListItem et qui réimplémentent les méthodes rowCount(), data(), flags(), setData(), insertRows(), removeRows(), mimeData() et dropMimeData().
    Mont but étant toujours d'effectuer un drag&drop d'un modèle à l'autre tout en copiant la QString glissée quand on la dépose.

    Il y a cependant plusieurs points, que j'ai remarqué pendant mes tests, qui restent flous :

    1) Le signal itemChanged() émis dans la méthode réimplémentée setData() met à jour la vue c'est bien ça ?
    Dans ce cas, pourquoi lorsque je commente dans la réimplémentation de dropMimeData() l'appel au setData() tout en rajoutant dans la méthode insertRows() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            for (int row = 0; row < rows; ++row) 
                _list.insert(position, "bonjour");
    la vue se met à jour quand même ? (en gros je ne passe pas par le setData mais seulement par le insertRows(). D'ailleurs, en quoi setData() se différencie de insertRows() ? Je pourrais très bien surcharger insertRows avec en paramètre la QString que je veux rajouter et dans ce cas je ne passe jamais par setData() ).

    2) Par ailleurs, j'ai effectué des tests en commentant les méthodes mimeData() et dropMimeData() et là, je constate que le drag and drop a quand même lieu entre mes deux modèles. Je peux glisser et déposer une ligne d'un modèle à l'autre. Avez-vous une explication ?

    Merci beaucoup

  5. #5
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    1) Étant donné qu'à chaque fois que paint() est appelé (souvent de nombreuses fois par seconde si tu bouges la fenêtre, la souris dessus...), il interroge le modèle pour dessiner son contenu, c'est normal que la liste se mette à jour quand même. Cependant si tu n'appelles pas toi-même update() dès qu'il y a un changement, il n'est pas garanti que ce changement apparaisse tout de suite (tant que rien ne déclenche le re-dessin de la zone concernée), c'est pourquoi en règle général on appelle update() dès qu'on a besoin de rafraichir, ça ne coûte rien (appeler update() se fait ici implicitement en avertissant du changement avec dataChanged()).

    setData() : à l'index voulu tu alloues la donnée.
    insertRows() : tu insères des lignes avant une autre ligne, donc c'est vraiment pour gérer l'insertion (décalage des index et tout). Par défaut elle ne fait rien, mais tu peux avoir envie de faire une telle opération après tout.

    Donc elles ne font pas vraiment la même chose (j'ai un peu répété la doc, il faut absolument la lire attentivement à l'avenir).

    2) Oui j'en ai une (mais je n'ai pas le temps de développer là, peut-être ce soir), tu peux te renseigner sur le rôle du mimedata dans un drag and drop (une zone de drop n'accepte pas n'importe quel mimedata, ça permet d'une part de définir le mimedata d'un item dans mimeData(), et d'autre part de filtrer les éléments dropés dans dropMimeData()). Si tu as enlevé les méthodes, essaye de droper n'importe quoi (une icône de ton bureau par exemple) dans ta liste, tu verras bien...

  6. #6
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    Merci encore Troudhyl pour ta clarté et ta rapidité

    1) Du coup, si je veux assurer l'update() dans insertRows, il faut donc que je rajoute le signal dataChanged() après le endInsertRows() j'imagine ? Cependant je n'ai pas de modelIndex en param de la méthode à lui passer, il me suffit de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    emit dataChanged(QModelIndex(), QModelIndex());
    ?

    2) Ok! je vais regarder plus attentivement la documentation pour que se soit plus clair. J'ai essayé de droper autre chose mais rien n'est accepté (îcône d'interdiction de drop dans la QTreeView). En fait ce que je trouve étrange c'est qu'il semble suffire d'accepter le drop dans la QTreeView pour que lors d'un drop la méthode insertRows réimplémentée (et non la surchargée) soit automatiquement appelée. (Un drop appel insertRows directement sans que je ne lui ai demandé)

    J'avais vu que mimeData permettait non seulement par l'intérmediaire de mimeTypes de définir le format accepté mais je pensais aussi que c'était vraiment par ce moyen que le drag & drop avait lieu.

    Au final, je suis quand même encore loin du résultat voulu. Tout ce que je fais pour l'instant c'est donc un appel automatique de insertRows() quand je drop et donc en aucun cas je récupère l'info sur le nom du champ de l'élément que je drag dans le modèle initial.. mais il semblerait que se soit le rôle du mimeData pour le coup!

    Mon explication serait donc peut être la suivante : mimeData et dropMimeData par défaut appel déjà bien insertRows si l'index du drop est pas occupé ou setData sinon avec l'échange d'un QString. Par contre, ce qui m'échappe c'est pourquoi le "value" en argument de setData() qui est appelé lors du drop sans redéfinition de mimData et dropMimeData est bien une QString et donc représentatif du format d'affichage plus que représentatif des données réelles du modèle ? (par données réelles, je veux dire qu'en membre j'ai une QList<Struct>.) Pourquoi value de setData n'est donc pas une Struct ?

    Merci pour ton aide encore

  7. #7
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    (C'est toi sfarc ?)

    1) T'es-tu demandé à quoi servent précisément beginInsertRows() et endInsertRows() ? Jette un coup d’œil sur l'implémentation de la deuxième, il devrait y avoir quelque chose qui provoque déjà un rafraichissement . Donc tu n'as pas à t'en préoccuper.

    2) Je te laisse continuer à chercher, apparemment QListView implémente déjà le drag and drop c'est pourquoi tu n'as pas grand chose à faire, il y a un fonctionnement par défaut. Ton histoire de "représentatif du format d'affichage" ne veut rien dire, c'est toi qui a défini ce qui s'affiche dans data() et surtout dans le delegate qui interprète le QVariant retourné par data() (donc qui le traduit en Struct, type que tu as enregistré).

  8. #8
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    Merci encore Troudhyl

    Non ce n'était pas moi mais un ami avec qui je fais ce projet donc au final on a le même problème

    1) Concernant le beginInsert et le endInsert, je vois ça comme une information por prévenir que le modèle a été mis à jour donc oui dans ce cas j'imagine que le delegate en est informé et rafraichit donc la vue non?

    2) Oui ça veut pas dire grand chose :p J'imagine que le mimData() et le dropMimeData() de base donc sans réimplémentation permet déjà d'effectuer le drag and drop avec le passage d'une QString en valeur. Par contre, les redéfinir est intéressant si on veut par exemple appeler un insertRows à la place d'un setData si le drop s'effectue à un index déjà occupé.

    Je rencontre cependant deux autres petits problèmes :

    3) Je me suis rendu compte que je pouvais droper dans mes champs de saisie la valeur glissée de ma QTreeView de base. J'ai donc effectuer un setAcceptDrops(false) et ils semblent ne plus accepter sauf un qu'il faut que je regarde de plus près. Par contre, plus délicat, je peux même droper en dehors de mon appli ! J'ouvre notepad, je fais un drag and drop et je drop la QString dans notepad, ce qui est embêtant quand même. Une idée pour éviter ça ?

    4) Enfin, maintenant, si dans mon QTreeView j'ai donc deux niveaux avec un noeud qui contient 3 fils et que je veux, lorsque je glisse le noeud de mon QTreeView1 au QTreeView2, que ce dernier ait au final la même arborescence et les mêmes valeurs QString qu'au départ ? Il suffit de fournir à mimeData un QString contenant chaque nom de champs (noeud + fils)pour les récupérer dans le dropMimeData et reconstruire l'arborescence dans cette dernière méthode ? Ou vaut-il mieux passer dans mimeData une donnée plus complexe qu'un QString et effectuer ensuite la même démarche que pour la première idée ?

    Merci beaucoup

  9. #9
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    1) Jette un œil dans les sources de Qt, ce n'était pas une devinette.

    2) Idem, pour t'aider je lirais la doc et les sources de ces fonctions, donc autant que tu le fasses pour vérifier tes hypothèses.

    3) C'est le but du Mime type. Le drag and drop c'est une fonctionnalité système comme le clic, la frappe clavier... Donc tu peux droper partout n'importe quoi de draggable. Pour blinder ton système, tu dois utiliser ton propre mime type, que tes QTreeView seront les seuls à utiliser. Ils rejetteront tous les drops extérieurs, et inversement.

    4) Au début de la discussion, on raisonnait avec des listes, mais dans un QTreeView les index ont des lignes, des colonnes et un parent (donc j'espère que tu as compris comment fonctionne l'indexation, les QModelIndex, dans un QTreeView). C'est sûr qu'à ce niveau-là, une QString ne te sert à rien, si c'est possible il te faudrait un pointeur sur le QModelIndex du nœud que tu drop, de façon à copier aussi tous ses fils.

    Au fait, dans data() et setData(), as-tu utilisé correctement les rôles (EditRole...) ? (pas le temps de regarder tes sources là) Eventuellement tu peux définir tes propres rôles ce qui ouvre encore de nouvelles possibilités.

  10. #10
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    Salut Troudhyl et encore merci

    3) En effet, j'ai réimplémenté mimeTypes et du coup seul ma QTreeView a connaissance des données

    4) En fait, pour revenir sur la situation, elle est différente de celle que je t'avais présenté. En fait, il n'y a qu'un QTreeView (celui dans lequel on drop) qui a une arborescence, l'autre ayant qu'un seul niveau.

    J'ai trouvé ce lien qui explique comment créer un tree model d'objet treeItem. Seulement, je vais avoir un problème dans mon cas. Le tout premier niveau de l'arborescence ne retourne pas la même information que son sous-niveau. Pour être plus clair, je vais avoir par exemple deux noeuds tout en haut (un pour une équipe, et l'autre pour la deuxième équipe) et c'est dans ces équipes que je vais venir "dropper" un nom pour mon objet correspondant au nom du QTreeView de niveau 1 ou on "drag". L'objet fait alors parti d'un équipe (sous noeud) et cet objet a des sous-noeuds correspondant à des informations sur lui.

    Exemple :

    - Equipe 1
    * Jean
    i- 17 ans
    ii- offensif
    iii- fatigué
    - Equipe 2
    * Paul
    i- 42 ans
    ii- défensif
    iii- en forme

    Bon les champs des objets "joueur" par exemple ici sont vraiment choisis au hasard, c'est un exemple. Mais du coup cela montre bien mon problème. Je ne sais pas comment m'y prendre pour définir un premier niveau de donnée (ici les équipes) et après "véritables" données du modèle, à savoir les joueurs.

    Par exemple, dans la réimplémentation de index avec un seul type de données :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    QModelIndex Model::index(int row, int column, const QModelIndex &parent) const{
     
      if (parent.isValid() && parent.column() != 0)
        return QModelIndex();
     
      Item* parentItem = getItem(parent);
     
      Item* childItem = parentItem->child(row);
     
      if (childItem)
        return createIndex(row, column, childItem);
      else
        return QModelIndex();
    }
     
    QVariant Model::data(const QModelIndex &index, int role) const{
     
      if (!index.isValid())
        return QVariant();
     
      if (role != Qt::DisplayRole && role != Qt::EditRole)
        return QVariant();
     
      Item* item = getItem(index);
     
      return item->data(index.column());
    }
     
    Item* Model::getItem(const QModelIndex &index) const{
     
      if (index.isValid()){
     
        Item* item = static_cast<OdbItem*>(index.internalPointer());
        if (item) return item;
      }
     
      return _rootItem;
    }
    Mais en faisant le getItem, je récupère que mon type de donnée item, alors que les premiers noeuds sur l'équipe ne font pas partie de ce type d'information.

    Peut être créer une QStringList equipes avec les noms d'équipes et rajouter dans data :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      if (!item){ // getItem n'a rien trouvé puisque les champs d'équipe ne sont pas de type Item
     
    return equipes[index.row()];
    }
    ?

    Merci

  11. #11
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    Tu dois simplement séparer le cas !index.parent().isValid() et index.parent().isValid() pour déterminer si tu parles d'une équipe (item de niveau 0) ou non, dans data().

  12. #12
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    Ok merci Troudhyl

    Bon, tel que je vois les choses pour l'instant, c'est que tout se passe par les TreeItem. Autrement dit, les TreeItems vont pour certains représenter des objets avec une information sur l'équipe, d'autres vont avoir pour information le nom d'un objet Joueur, et enfin les derniers auront pour information les champs de l'objet Joueur.
    Au final, seul la data va changer pour chaque TreeItem selon son niveau d'arborescence (niveau 1 -> equipe, niveau 2 -> nom d'un objet Joueur, niveau 3 -> champ d'un objet Joueur).
    Aussi, pour savoir quelle donnée insérer entre une équipe, un nom de joueur et un champ du joueur, dans insertRows par exemple, je regarde la profondeur de l'index.
    Jusque là, est-ce que ma vision est juste ?

    Il reste cependant un dernier point qui m'échappe. Tel que c'est fait pour le moment, je manipule donc des TreeItem qui forment mon TreeModel. Seulement, lorsque j'insère un ou des TreeItem ou que je les remove via insertRows(), removeRows(), voir d'autres surcharges utiles, l'action n'a aucune influence sur ma structure de données formée par ma liste d'objets Joueurs. Comment rentre ce modèle plus adapté afin que quand j'insère un TreeItem, Je créé un objet Joueur avec les champs qui vont bien, lorsque je remove un TreeItem à un index donné, je retrouve bien dans ma liste de Joueurs le joueur concerné ?

    Dois-je faire une sorte de lien entre un TreeItem et un objet Joueur ? comme un QMap par exemple ? Ou sinon, connaissez-vous la méthode appropriée ?

    Merci beaucoup

  13. #13
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    Les codes tout fait c'est bien parfois pour approfondir en profitant de l'expérience de quelqu'un et de ses bonnes idées, mais là pour débuter tu perds de vue l'idée de base du modèle/vue.

    La classe TreeItem en fait c'est quoi ? Peu importe le code, c'est exactement l'équivalent de ta Struct de départ, à savoir formater les données. L'accès aux données reste géré entièrement par la surcouche modèle, mais son formatage est libre par contre. Tu peux très bien rester avec une succincte struct si ça te suffit, où y rajouter des méthodes (c'est-à-dire faire une classe, qu'on me reprenne si je dis de grosses bêtises, je suis plutôt débutant aussi).

    Donc ta classe Item, t'en fais ce que tu veux, t'y mets les données membres que tu veux, tu fais les calculs que tu veux... C'est de la pure conception, il n'y a pas de bonne ou mauvaise méthode, c'est selon le problème. L'exemple très générique de TreeItem que tu as trouvé t'aide en fait à te poser des questions comme "est-ce que dans l'item, j'ai besoin d'accesseurs vers son parent ou ses enfants, ou des données sur sa position dans l'arborescence ?" etc.

    Je rajoute que s'il te faut une classe Joueur, une Equipe etc à la place d'une seule Item (vraiment trop générique), pas de souci, t'es libre. Sachant que l'internalPointer de l'index, que tu utilises, est un void*, il te suffit de savoir quand le caster en Equipe* ou en Joueur*...

  14. #14
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    Salut et merci encore Troudhyl

    Je comprends mieux ! Juste un derniers points et je pense pouvoir me lancer dans l'implémentation :

    Dans mon cas par exemple, je vais avoir des objets Equipes possèdant une QList de Joueurs avec des propriétés. Le rapport entre les deux est donc clair et sera assez facilement intégré à mon modèle. Le seul soucis c'est les paramètres membres de Joueurs que je veux faire apparaître en noeud fils de mes Joueurs.

    Il me paraitrait bizarre de définir un item à nouveau pour mes params dans le tree model mais en même temps je ne vois pas bien comment faire sans .. Comment gérer les liens de parenté sinon par exemple. En même temps, ça paraît pas très cohérent de redéfinir des items pour les infos des paramètres de l'objet Joueur lui même étant donné qu'ils font partie du Joueur.

    Mais comment gérer ses données vis à vis du Joueur dans l'arbre sans pour autant redéfinir des items pour les représenter ?

    Merci!

  15. #15
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    Dans le data() ou le setData() :
    Tu analyses l'index, si c'est niveau 0 c'est une Equipe, si c'est niveau 1 (un parent mais pas de grand-parent), c'est un Joueur, et sinon alors c'est une donnée de joueur.

    Dans le index(), tu peux le redéfinir pour les niveaux 0 et 1 de façon à ce qu'il enregistre dans son internalPointer le pointeur vers l'Equipe ou le Joueur respectivement. Pour les niveaux en-dessous tu laisses par défaut, rien à enregistrer.

    De retour dans data() et setData() :
    Si donc c'est une donnée de joueur, tu récupères l'internalPointer de l'index parent (le joueur, si je suis bien), et tu en appelles les accesseurs.

  16. #16
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    De retour dans data() et setData() :
    Si donc c'est une donnée de joueur, tu récupères l'internalPointer de l'index parent (le joueur, si je suis bien), et tu en appelles les accesseurs.
    Justement, l'internalPointeur de l'index pour une donnée d'un joueur ne va rien me retourner puisque ce n'est ni une Equipe ni un Joueur.

    Comme je le comprends quand tu dis :

    Dans le index(), tu peux le redéfinir pour les niveaux 0 et 1 de façon à ce qu'il enregistre dans son internalPointer le pointeur vers l'Equipe ou le Joueur respectivement. Pour les niveaux en-dessous tu laisses par défaut, rien à enregistrer.
    Du coup,l'index n'est pas définit pour une donnée de Joueur, ou représente le même que la racine vu qu'on laisse celui par défaut. Aussi, même avec un index sur ces données, on ne sait pas quel est l'index parent, autrement dit le Joueur auquel elles font référence, puisqu'on a définit aucun item représentant ces données avec un accesseur au parent. Comment le modèle peut s'y retrouver du coup?

  17. #17
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    De retour dans data() et setData() :
    Si donc c'est une donnée de joueur, tu récupères l'internalPointer de l'index parent (le joueur, si je suis bien), et tu en appelles les accesseurs.
    index.parent()

  18. #18
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    index.parent()
    Oui c'est vrai :p mais en faisant ça, tu supposes que index est valide. Or, en réimplémentant index(), on a retourné un QModelIndex() pour une donnée qui n'est donc pas une Equipe ou un Joueur.

    Dans le index(), tu peux le redéfinir pour les niveaux 0 et 1 de façon à ce qu'il enregistre dans son internalPointer le pointeur vers l'Equipe ou le Joueur respectivement. Pour les niveaux en-dessous tu laisses par défaut, rien à enregistrer.
    Les index ne sont donc pas bien définis pour les données et donc le parent n'est pas accessible facilement si ?

  19. #19
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2009
    Messages : 1 009
    Points : 1 738
    Points
    1 738
    Par défaut
    L'implémentation d'index() n'est pas bonne pour ce que tu veux faire là, tu ne dois pas renvoyer quelque chose d'invalide alors que c'est valide (ça fait partie de l'arborescence). C'est l'objet de l'étape "Dans le index()", revoir cette fonction pour en faire ce que tu as besoin. Après je te dis que pour une donnée de joueur, t'enregistres rien dans l'internalPointer mais ça c'est toi qui vois, tu pourrais enregistrer le joueur aussi. T'es libre.

  20. #20
    Membre confirmé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Points : 528
    Points
    528
    Par défaut
    L'implémentation d'index() n'est pas bonne pour ce que tu veux faire là, tu ne dois pas renvoyer quelque chose d'invalide alors que c'est valide (ça fait partie de l'arborescence)
    Je dois mal comprendre alors. Qu'est ce que tu entends exactement par "enregistrer dans l'internalPointer" ? Tout ce que fait la méthode index c'est de retourner un QModelIndex valide (représentant l'index d'un élément) ou non valide (QModelIndex()).

    Donc quand avec l'index du parent je retrouve un Joueur, je fais un createIndex() avec un pointeur sur mon joueur. Et quand j'ai un index du parent qui est sur un Joueur, je suis dans le cas ou il faut que je créé un index sur l'un des champs. Je fais donc un createIndex toujours c'est ça ? Par contre ce n'est plus un pointeur sur un objet que je vais passer.

Discussions similaires

  1. Réponses: 6
    Dernier message: 25/11/2014, 11h36
  2. Glisser-déposer entre QWidget différents
    Par EvaBraun dans le forum Débuter
    Réponses: 1
    Dernier message: 24/11/2012, 10h59
  3. Glisser-déposer entre deux zones de listes
    Par Arkham46 dans le forum Contribuez
    Réponses: 2
    Dernier message: 13/04/2012, 12h20
  4. Glisser-déposer entre ListView
    Par Troudhyl dans le forum Qt Quick
    Réponses: 5
    Dernier message: 18/01/2012, 13h01
  5. Réponses: 5
    Dernier message: 25/03/2003, 19h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo