<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://doc.qtfr.org/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
  <title>Documentation Qtfr - modèle-vue</title>
  <link>http://doc.qtfr.org/</link>
  <description>La documentation francophone sur Qt</description>
  <language>fr</language>
  <pubDate>Thu, 06 Nov 2008 23:03:54 +0100</pubDate>
  <copyright></copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Introduction aux MVC et création d'un modèle hiérarchique simple</title>
    <link>http://doc.qtfr.org/post/2007/12/16/Creation-dun-modele-hierarchique-simple-base-sur-QAbstractItemModel</link>
    <guid isPermaLink="false">urn:md5:df641f7821f791d36e6b449eb2e1ffd8</guid>
    <pubDate>Sun, 16 Dec 2007 17:02:00 +0100</pubDate>
    <dc:creator>Guid</dc:creator>
        <category>Tutoriels</category>
        <category>class_QAbstractItemModel</category><category>class_QModelIndex</category><category>class_QTreeView</category><category>modèle-vue</category><category>version_Qt4</category>    
    <description>&lt;p&gt;Ce document présente le concept général de MVC, puis s'attarde sur celui de Qt 4 et enfin, une mise en oeuvre simple du &lt;code&gt;QAbstractItemModel&lt;/code&gt; est expliquée en détail et est basée sur sur l'exemple officiel Qt &quot;simpletreemodel&quot;.&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;Version&lt;/strong&gt;&amp;nbsp;: Toutes versions à partir de Qt 4.0 (exemple fait avec C++/Qt 4.3.3)&lt;br /&gt;
&lt;strong&gt;Auteur&lt;/strong&gt;&amp;nbsp;: Guillaume -Guid- DENRY (sur le forum, &lt;a href=&quot;http://forum.qtfr.org/profile.php?id=396&quot;&gt;Azuriel&lt;/a&gt;)&lt;br /&gt;&lt;/p&gt;    &lt;h2&gt;Présentation&lt;/h2&gt;


&lt;p&gt;L'affichage et la manipulation de données est une problèmatique aussi vieille que l'informatique elle-même.
En 1979, une tentative de formalisation de ce domaine aboutit au concept de &lt;acronym title=&quot;Model-View-Controller&quot;&gt;MVC&lt;/acronym&gt; (littéralement Modèle-Vue-Controlleur) qui prend tout d'abord &lt;a href=&quot;http://st-www.cs.uiuc.edu/users/smarch/st-docs/mvc.html&quot; hreflang=&quot;en&quot;&gt;naissance dans le monde smalltalk&lt;/a&gt;, et qui permet de dissocier les données de la présentation ainsi que de la logique de contrôle.
Cette stratégie permet un découpage clair des concepts et de leurs implémentations, mais surtout une factorisation du code; le fameux concept
&lt;a href=&quot;http://en.wikipedia.org/wiki/DRY_code&quot; hreflang=&quot;en&quot;&gt;DRY&lt;/a&gt; cher à Ruby, ainsi, alors que le &lt;em&gt;modèle&lt;/em&gt; est entièrement dévoué à fournir des données et à en accepter, la &lt;em&gt;vue&lt;/em&gt; est uniquement concentrée sur la façon d'afficher les données (c'est la partie émergée de l'iceberg pour l'utilisateur de l'application) tandis que le &lt;em&gt;controlleur&lt;/em&gt;, tel un arbitre, se charge de synchroniser les évènements entre le &lt;em&gt;modèle&lt;/em&gt; et la &lt;em&gt;vue&lt;/em&gt;.&lt;/p&gt;


&lt;p&gt;Qt 4 a choisi d'utiliser ces concepts au sein de plusieurs de ses composants de manipulation et d'affichage de données. Dans la bibliothèque de Trolltech, le C du MVC se retrouve combiné au V pour des raisons de praticité et on parle ainsi de &lt;a href=&quot;http://doc.trolltech.com/4.3/model-view-programming.html&quot; hreflang=&quot;en&quot;&gt;''Modèle/Vue''&lt;/a&gt;.
A ces concepts se voit adjoint celui de &lt;em&gt;delegate&lt;/em&gt; qui définit concrètement la façon dont sont présentées et éditées les données (par exemple via une liste déroulante, une cellule d'édition, etc).&lt;/p&gt;


&lt;p&gt;On trouve plusieurs composants de type &quot;vue&quot;&amp;nbsp;; voici ceux que l'on peut trouver dans la dernière version de Qt 4 au moment où est écrit ce tutoriel (4.3.3)&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le &lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qtableview.html&quot; hreflang=&quot;en&quot;&gt;QTableView&lt;/a&gt;&lt;/code&gt; qui permet d'afficher un ensemble de données sous forme de tableau et sans notion de hiérarchie.&lt;/li&gt;
&lt;li&gt;Le &lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qtreeview.html&quot; hreflang=&quot;en&quot;&gt;QTreeView&lt;/a&gt;&lt;/code&gt; modélise un ensemble de données hiérarchisées sous forme d'arbre.&lt;/li&gt;
&lt;li&gt;Le &lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qlistview.html&quot; hreflang=&quot;en&quot;&gt;QListView&lt;/a&gt;&lt;/code&gt; affiche des données sous forme de liste, exactement comme le mode &quot;liste&quot; d'un explorateur de fichiers.&lt;/li&gt;
&lt;li&gt;Le &lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qcolumnview.html&quot; hreflang=&quot;en&quot;&gt;QColumnView&lt;/a&gt;&lt;/code&gt; qui affiche une succession de QListViews pour afficher une hiérarchie, à l'instar de Finder, le fameux navigateur de fichiers de MacOSX ou de celui de l'Ipod.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Il est à noter que tous ces composants trouvent leurs équivalents déjà affectés de modèles simples et qui peuvent être amplement suffisants pour un usage de base. Si vous cherchez un moyen simple d'afficher des données sans vous soucier d'optimisation, de maintenabilité, de paramétrage fin et si concevoir un système MVC ne vous séduit pas plus que cela, ce tutoriel n'est peut-être pas tout-à-fait indiqué et vous devriez peut-être vous pencher sur les &lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qtablewidget.html&quot; hreflang=&quot;en&quot;&gt;QTableWidget&lt;/a&gt;&lt;/code&gt;/&lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qtreewidget.html&quot; hreflang=&quot;en&quot;&gt;QTreeWidget&lt;/a&gt;&lt;/code&gt;/&lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qlistwidget.html&quot; hreflang=&quot;en&quot;&gt;QListWidget&lt;/a&gt;&lt;/code&gt; qui offrent déjà pas mal de possibilités.&lt;/p&gt;


&lt;p&gt;L'utilisation des modèles dans Qt passe systématiquement par l'héritage d'un des modèles Qt dont l'ancêtre commun est toujours la classe abstraite &lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qabstractitemmodel.html&quot; hreflang=&quot;en&quot;&gt;QAbstractItemModel&lt;/a&gt;&lt;/code&gt;.&lt;br /&gt;
La plupart du temps, vous n'aurez pas besoin d'hériter des vues ainsi que de définir de nouveaux &lt;em&gt;delegates&lt;/em&gt; (ni même vous en soucier pour ces derniers); ceux qui existent déjà suffisent pour la plupart des usages. Néammoins, ce besoin pourra se faire sentir dans certaines circonstances, c'est pourquoi l'écriture d'un delegate particulier et son intégration au sein d'une vue sera abordé dans un autre tutoriel.&lt;/p&gt;


&lt;p&gt;Le concept de MVC est abondamment expliqué dans la documentation officielle Qt et la création d'un modèle simple non hiérarchique est relativement simple à appréhender. Il se peut même que vous n'ayez pas besoin de ce tutoriel car les exemples de Qt en ce qui concerne les modèles/vues sont nombreux et je vous recommande de jeter un oeil aux exemples situés dans le répertoire itemviews du tarball officiel si le parcours d'un tutoriel n'est pas votre tasse de thé.&lt;br /&gt;
Ainsi, tout au long de ce document, nous allons nous concentrer sur le QTreeView et sur la création d'un modèle hiérarchique afin d'expliciter quelques points qui peuvent paraître obscures lorsqu'on s'initie à leur création. Nous tâcherons ainsi d'éclaircir le rôle des diverses méthodes virtuelles à hériter obligatoirement (méthodes abstraites) ou de façon optionnelle afin d'affiner le comportement de notre modèle.&lt;/p&gt;


&lt;h2&gt;Rétro-conception&lt;/h2&gt;


&lt;p&gt;Puisqu'il va falloir indiquer au modèle où trouver nos données et comment se représenter la hiérarchie de celles-ci, il est crucial d'avoir déjà une idée claire et précise de la façon dont nos données sont agencées en mémoire et ce qui les lie les unes aux autres.&lt;br /&gt;
Du côté du modèle, le &lt;code&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qmodelindex.html&quot; hreflang=&quot;en&quot;&gt;QModelIndex&lt;/a&gt;&lt;/code&gt; nous offre un moyen simple de mettre en oeuvre les briques élémentaires de la modélisation de nos données.&lt;br /&gt;
Cette classe est le lien entre la donnée élémentaire et le modèle, mais &lt;ins&gt;ne se substitue pas&lt;/ins&gt; à la donnée en elle-même; il est primordial de concevoir une structure de données hiérarchiques interne qui sera utilisée par notre modèle pour créér ses index.&lt;br /&gt;
De façon plus formelle, le &lt;code&gt;QModelIndex&lt;/code&gt; connaît le modèle auquel il appartient, son père&lt;sup&gt;[&lt;a href=&quot;http://doc.qtfr.org/post/2007/12/16/#pnote-171-1&quot; id=&quot;rev-pnote-171-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;, son numéro de ligne (au sein des enfants de ce père, pas le numéro de ligne absolu dans le modèle) ainsi que son numéro de colonne.
Voilà en gros tout dont le modèle a besoin pour construire sa hiérarchie et on expliquera les rôles des autres champs ultérieurement. Pour la suite, pour évoquer le &lt;code&gt;QModelIndex&lt;/code&gt; on parlera simplement d&lt;em&gt;'index&lt;/em&gt;.&lt;/p&gt;


&lt;p&gt;Les structures internes de nos données devront refléter ces propriétés relationnelles, par exemple, il sera indispensable qu'on puisse facilement retrouver le père d'un élément de données. Ranger nos données dans un structure arborescente est donc probablement le meilleur des choix. S'il n'est pas possible de stocker toutes les données en mémoire (typiquement dans le cas d'une base de données), il faudra tout de même pouvoir modéliser ces concepts relationnels &quot;facilement&quot;.&lt;/p&gt;


&lt;p&gt;Comme nous l'avons vu plus haut, concevoir un modèle dans Qt 4, c'est hériter, directement ou indirectement, de la classe &lt;code&gt;QAbstractItemModel&lt;/code&gt; et implémenter un lot de méthodes virtuelles dont certaines sont &lt;em&gt;abstraites&lt;/em&gt; et donc doivent être impérativement héritées sous peine d'erreur de la part du compilateur.&lt;/p&gt;


&lt;p&gt;Ces fonctions abstraites sont&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;QModelIndex &lt;a href=&quot;http://doc.trolltech.com/4.3/qabstractitemmodel.html#index&quot; hreflang=&quot;en&quot;&gt;index&lt;/a&gt;(int row, int column, const QModelIndex &amp;amp; parent = QModelIndex())&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C'est un peu l'&quot;usine à index&quot; du modèle. Ici vont être créés puis renvoyés les index en fonction d'un numéro de ligne, de colonne et d'un index père.
A chaque fois que l'on aura besoin d'un index quelque part, que ce soit dans le modèle ou à l'extérieur de ce modèle, c'est cette méthode qui sera invoquée (à l'exception de la création des index pères qui seront fabriqués par le biais de la fonction &lt;code&gt;parent()&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;QModelIndex &lt;a href=&quot;http://doc.trolltech.com/4.3/qabstractitemmodel.html#parent&quot; hreflang=&quot;en&quot;&gt;parent&lt;/a&gt;(const QModelIndex &amp;amp; index)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette méthode est utilisée pour retrouver un index père en fonction de son fils.
Comme nous l'avons vu plus haut dans l'encadré, cette méthode est directement appelée par la méthode &quot;parent()&quot; de chaque QModelIndex appartenant au modèle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;int &lt;a href=&quot;http://doc.trolltech.com/4.3/qabstractitemmodel.html#rowCount&quot; hreflang=&quot;en&quot;&gt;rowCount&lt;/a&gt;(const QModelIndex &amp;amp; parent = QModelIndex())&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette fonction renvoie le nombre de lignes de l'index père passé en paramètre qu'on peut assimiler au nombre d'index enfants de ce père.
Cette méthode peut également se révéler couteuse et dans ce cas, il est parfois utile d'envisager la redéfinition de la méthode &quot;hasChildren()&quot; (cette méthode fait appel à rowCount() dans son implémentation par défaut) qui permet de signaler au modèle qu'un index a des enfants sans pour autant en spécifier combien, et ainsi par exemple afficher un noeud dans la vue qui, impliquera alors un appel à rowCount().&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;int &lt;a href=&quot;http://doc.trolltech.com/4.3/qabstractitemmodel.html#columnCount&quot; hreflang=&quot;en&quot;&gt;columnCount&lt;/a&gt;(const QModelIndex &amp;amp; parent = QModelIndex())&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette méthode renvoie le nombre de colonnes des enfants de l'index père passé en paramètre. Dans la plupart des cas, cette méthode renverra un nombre non dépendant du père.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;QVariant &lt;a href=&quot;http://doc.trolltech.com/4.3/qabstractitemmodel.html#data&quot; hreflang=&quot;en&quot;&gt;data&lt;/a&gt;(const QModelIndex &amp;amp; index, int role = Qt::DisplayRole)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C'est probablement la fonction la plus sollicitée pendant la vie du modèle; elle permet de connaître les données à afficher dans la vue en fonction d'un index et d'un &lt;em&gt;rôle&lt;/em&gt;.&lt;br /&gt;
Les &lt;em&gt;&lt;a href=&quot;http://doc.trolltech.com/4.3/qt.html#ItemDataRole-enum&quot; hreflang=&quot;en&quot;&gt;rôles&lt;/a&gt;&lt;/em&gt; définissent dans les détails la façon dont une donnée est présentée par les vues associées. On peut par exemple invoquer la méthode &lt;code&gt;data()&lt;/code&gt; pour demander la valeur du texte à afficher par le biais de &lt;code&gt;Qt::DisplayRole&lt;/code&gt; ou alors la couleur de fond de la cellule qui accueuillera le texte avec le paramètre &lt;code&gt;Qt::BackgroundRole&lt;/code&gt;, ou si nécessaire, la police de caractère à utiliser grâce à &lt;code&gt;Qt::FontRole&lt;/code&gt;.&lt;br /&gt;
Les rôles ont été conçus pour être les plus exhaustifs et génériques possibles mais il est possible de les étendre à partir de la valeur &lt;code&gt;Qt::UserRole&lt;/code&gt; qui constitue le premier role &quot;utilisateur&quot;.&lt;br /&gt;
Dans le cas d'une utilisation classique, le rôle essentiel est &lt;code&gt;Qt::DisplayRole&lt;/code&gt; car il concerne directement la donnée (très souvent et en particulier ici du texte) à afficher dans la vue.&lt;br /&gt;
Il faut également garder à l'esprit que &lt;code&gt;data()&lt;/code&gt; étant appelée très fréquemment, il est important de ne pas y trouver de traitements lourds. Typiquement, je ne fais aucun appel aux outils de traduction dans cette méthode, je les déporte dans le constructeur du modèle.&lt;/p&gt;


&lt;p&gt;Puisque Trolltech nous fournit déjà des exemples et des démonstrations de qualité, nous allons appuyer ce tutoriel sur la démo
&lt;a href=&quot;http://doc.trolltech.com/4.3/itemviews-simpletreemodel.html&quot; hreflang=&quot;fr&quot;&gt;simpletreemodel&lt;/a&gt; (sur cette page, vous trouverez également une bonne explication en anglais de cet exemple) disponible dans tout tarball Qt (et dans certains paquets) afin d'expliquer en détail l'implémentation du modèle et les choix effectués.&lt;/p&gt;


&lt;h2&gt;simpletreemodel&lt;/h2&gt;


&lt;h3&gt;Description&lt;/h3&gt;


&lt;p&gt;Cet exemple charge et affiche le contenu dans un arbre (&lt;code&gt;QTreeView&lt;/code&gt;) d'un fichier de type &quot;Sommaire&quot; de livre.
Ce fichier est un ensemble de lignes de texte plus ou moins en retrait par le biais de caractères d'espacement.
Par exemple, une ligne qui commence par 8 espaces et qui précède une ligne qui débute par 4 espaces sera considérée comme &quot;fille&quot; de la ligne précédente.
Chaque ligne de texte est séparée en deux par un ensemble de tabulations, cet ensemble de tabulation permettra de diviser la ligne en deux colonnes dans l'arbre.
Ainsi nous avons donc un arbre à deux colonnes décrit au sein d'un fichier texte et dont voici un extrait&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
Form Editing Mode                       How to edit a form in Qt Designer
    Managing Forms                      Loading and saving forms
...
    Layouts                             Objects that arrange widgets on a form
        Applying and Breaking Layouts   Managing widgets in layouts
&lt;/pre&gt;


&lt;h3&gt;Exécution&lt;/h3&gt;


&lt;p&gt;Au lancement du programme, un modèle (implémenté dans treemodel.h/treemodel.cpp) est créé avec en paramètre le texte du fichier &quot;default.txt&quot; chargé pour l'occasion. Ce texte est &quot;parsé&quot; (analysé et stocké dans une structure de données) pendant la construction du modèle, ce qui permettra son utilisation immédiate plus tard sans autre forme d'initialisation.
Puis, un &lt;code&gt;QTreeView&lt;/code&gt; est également créé et on lui affecte le modèle.
On attribue un titre à cet arbre puis il est affiché et la boucle d'évènements est lancée; le programme est réellement visuellement disponible à ce moment là et nous pouvons voir à l'écran le &lt;code&gt;QTreeView&lt;/code&gt; en action et le manipuler à notre guise.&lt;/p&gt;


&lt;h3&gt;Analyse&lt;/h3&gt;


&lt;h4&gt;Le stockage des données&lt;/h4&gt;


&lt;p&gt;Examinons tout d'abord le contenu de treeitem.h/.cpp.
La classe &lt;code&gt;TreeItem&lt;/code&gt; est conçue pour stocker une hiérarchie de données. Voici ses caractéristiques&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;parentItem&lt;/code&gt; pointe vers son élément père.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;childItems&lt;/code&gt; est une liste de pointeurs vers les fils de cet élément.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;itemData&lt;/code&gt; contient les données de l'élément sous forme de liste de QVariant (qui est le type générique de Qt, voir la documentation).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour cet exemple, l'auteur aurait pu se contenter pour &lt;code&gt;itemData&lt;/code&gt; d'une liste de &lt;code&gt;QString&lt;/code&gt;, mais le &lt;code&gt;QVariant&lt;/code&gt; permet d'imaginer un enrichissement de l'exemple afin de pouvoir stocker et afficher des types de données hétéroclytes au sein de la même liste. Il permet surtout d'être directement renvoyé par la méthode &lt;code&gt;data()&lt;/code&gt; du modèle sans aucune conversion comme nous le verrons plus tard.
A l'image d'une liste chaînée, l'arbre entier est accessible par sa racine et lorsqu'on détruit un &lt;code&gt;TreeItem&lt;/code&gt;, ses enfants sont également détruits. Notez à ce titre l'utilisation de &lt;code&gt;qDeleteAll()&lt;/code&gt;, fonction bien pratique qui permet de détruire tous les objets pointés stockés dans une structure de données Qt (QList, QVector, etc).&lt;/p&gt;


&lt;p&gt;Voilà qui permet de conclure sur cette classe &quot;jumelle&quot; à la hiérarchie des index et qui servira de conteneur de données librement consultable par le modèle de notre vue.&lt;/p&gt;


&lt;h4&gt;Le modèle&lt;/h4&gt;


&lt;p&gt;Intéressons-nous maintenant à la classe &lt;code&gt;TreeModel&lt;/code&gt; définie dans treemodel.h/.cpp.&lt;/p&gt;


&lt;p&gt;La méthode &lt;code&gt;setupModelData()&lt;/code&gt; contient le code le plus complexe de l'exemple :-), il analyse le texte en paramètre et en déduit une hiérarchie de TreeItems qu'il lie au noeud parent passé en paramètre. Cette fonction est appelée uniquement dans le constructeur avec &lt;code&gt;rootData&lt;/code&gt; préalablement créé. Ce noeud racine sera le point d'accès à l'arbre de données pour le modèle.&lt;/p&gt;


&lt;p&gt;En dehors de &lt;code&gt;setupModelData()&lt;/code&gt;, le reste des méthodes présentes sont des éléments hérités appartenant au &lt;code&gt;QAbstractItemModel&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;


&lt;h5&gt;La méthode &lt;code&gt;parent()&lt;/code&gt;&lt;/h5&gt;

&lt;pre class=&quot;cpp&quot;&gt;QModelIndex TreeModel::&lt;span style=&quot;color: #00eeff;&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt; QModelIndex &amp;amp;index&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;!index.&lt;span style=&quot;color: #00eeff;&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; QModelIndex&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;Le but de la méthode &lt;code&gt;parent()&lt;/code&gt; est de créer et renvoyer un &lt;code&gt;QModelIndex&lt;/code&gt; correspondant au père du &lt;code&gt;QModelIndex&lt;/code&gt; en paramètre.
Si l'index en paramètre est considéré comme orphelin dans l'arbre, alors il convient de renvoyer un index invalide.
Dans notre cas, un index racine est un index correspondant à un &lt;code&gt;TreeItem&lt;/code&gt; dont le père est &lt;code&gt;rootData&lt;/code&gt;.
&lt;code&gt;rootData&lt;/code&gt; est le seul élément dans tout l'arbre des &lt;code&gt;TreeItem&lt;/code&gt; qui n'a aucun &lt;code&gt;QModelIndex&lt;/code&gt; correspondant, il sert juste de père ultime référent et donc, les vrais éléments racines de l'arbre affichés à l'écran sont ses enfants directs.
&lt;code&gt;parent()&lt;/code&gt; est également une méthode publique. Rien que pour cette raison il est important de tester le cas où l'index en paramètre est invalide.
Le père d'un index invalide est donc naturellement ... un index invalide, créé par le biais du constructeur vide du &lt;code&gt;QModelIndex&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;TreeItem *childItem = static_cast&amp;lt;TreeItem*&amp;gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;index.&lt;span style=&quot;color: #00eeff;&quot;&gt;internalPointer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
    TreeItem *parentItem = childItem-&amp;gt;parent&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;internalPointer&lt;/code&gt; est une variable qui fait le lien entre l'index et la donnée. Chaque index du modèle sera donc lié à un &lt;code&gt;TreeItem&lt;/code&gt; cette liaison est faite à deux endroits du modèle; la méthode &lt;code&gt;index()&lt;/code&gt; et la méthode &lt;code&gt;parent()&lt;/code&gt;.
La première instruction se contente donc de récupérer le &lt;code&gt;TreeItem&lt;/code&gt; associé à l'index, en passant par un &lt;code&gt;static_cast&lt;/code&gt;, plus rapide qu'un &lt;code&gt;dynamic_cast&lt;/code&gt; et suffisant ici.
Il existe un autre moyen de lier une donnée à un index, &lt;code&gt;internalId&lt;/code&gt; qui est une autre propriété du &lt;code&gt;QModelIndex&lt;/code&gt;, utile dans les cas où la donnée serait accessible via un identificateur entier et non un pointeur. (on peut imaginer une clef entière dans une base de donnée, par exemple).
La seconde instruction stocke le père du &lt;code&gt;TreeItem&lt;/code&gt; prédédemment extrait dans &lt;code&gt;parentItem&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;parentItem == rootItem&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; QModelIndex&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;Nous avons vu que chaque &lt;code&gt;TreeItem&lt;/code&gt; pointe vers son père, si l'élément père est &lt;code&gt;rootItem&lt;/code&gt;, alors on considère du point de vue du modèle que l'index correspondant est un noeud racine et donc, on renvoie un &lt;code&gt;QModelIndex&lt;/code&gt; invalide.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; createIndex&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;parentItem-&amp;gt;row&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #0000dd;&quot;&gt;0&lt;/span&gt;, parentItem&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;createIndex()&lt;/code&gt;&lt;sup&gt;[&lt;a href=&quot;http://doc.qtfr.org/post/2007/12/16/#pnote-171-2&quot; id=&quot;rev-pnote-171-2&quot;&gt;2&lt;/a&gt;]&lt;/sup&gt; est une méthode qui permet de créer en une instruction un &lt;code&gt;QModelIndex&lt;/code&gt; attaché au modèle.&lt;/p&gt;


&lt;p&gt;La méthode &lt;code&gt;row()&lt;/code&gt; du TreeItem renvoie le numéro de ligne de l'élément au sein de ses frères et c'est exactement ce que &lt;code&gt;createIndex&lt;/code&gt; attend comme premier paramètre.
0 est passé comme numéro de colonne car le père d'un index est par convention toujours de colonne 0 dans un système hiérarchique conventionnel.
Et enfin, &lt;code&gt;parentItem&lt;/code&gt; est passé en tant que comme pointeur interne, c'est un des deux endroits dans le code où l'on associe un &lt;code&gt;TreeItem&lt;/code&gt; à son &lt;code&gt;QModelIndex&lt;/code&gt;.&lt;/p&gt;


&lt;h5&gt;La méthode &lt;code&gt;index()&lt;/code&gt;&lt;/h5&gt;

&lt;pre class=&quot;cpp&quot;&gt;QModelIndex TreeModel::&lt;span style=&quot;color: #00eeff;&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt; row, &lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt; column, &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt; QModelIndex &amp;amp;parent&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;!hasIndex&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;row, column, parent&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; QModelIndex&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;La méthode &lt;code&gt;index()&lt;/code&gt; est publique. Il convient donc de tester ses paramètres afin de résoudre les cas invalides.
En particulier, nous aimerions savoir si les paramètres &lt;code&gt;row&lt;/code&gt; et &lt;code&gt;column&lt;/code&gt; ne sortent pas des limites du modèle et heureusement, pour le savoir, il existe la fonction &lt;code&gt;hasIndex()&lt;/code&gt; qui nous renseigne à ce sujet. La documentation étant peu locace pour cette fonction, c'est dans les sources de Qt que nous allons trouver son rôle précis; cette méthode renvoie vrai si et seulement si les paramètres &lt;code&gt;row&lt;/code&gt; et &lt;code&gt;column&lt;/code&gt; sont compris entre 0 et le nombre maximum de lignes et de colonnes du parent passé en paramètre.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;TreeItem *parentItem;
&amp;nbsp;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;!parent.&lt;span style=&quot;color: #00eeff;&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        parentItem = rootItem;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;
        parentItem = static_cast&amp;lt;TreeItem*&amp;gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;parent.&lt;span style=&quot;color: #00eeff;&quot;&gt;internalPointer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;Ici nous avons besoin de récupérer l'élément de type &lt;code&gt;TreeItem&lt;/code&gt; correspondant à l'index que nous allons renvoyer.
Nous savons que si le paramètre &lt;code&gt;parent&lt;/code&gt; est valide, alors il aura été créé avec &lt;code&gt;parent()&lt;/code&gt; et possèdera donc en pointeur interne sur son &lt;code&gt;TreeItem&lt;/code&gt; &quot;jumeau&quot; et, dans le cas où &lt;code&gt;parent&lt;/code&gt; est invalide, c'est &lt;code&gt;rootItem&lt;/code&gt; qui jouera ce rôle.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;TreeItem *childItem = parentItem-&amp;gt;child&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;row&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;childItem&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; createIndex&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;row, column, childItem&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; QModelIndex&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Maintenant que nous avons l'élément père ainsi que le numéro de ligne du fils, il est trivial d'en déduire l'élément fils avec la méthode &lt;code&gt;child()&lt;/code&gt;. Par prudence, le retour de cette méthode est testé et &lt;code&gt;createIndex()&lt;/code&gt; est à nouveau invoqué puis retourné par la fonction.&lt;/p&gt;


&lt;h5&gt;La méthode &lt;code&gt;data()&lt;/code&gt;&lt;/h5&gt;

&lt;pre class=&quot;cpp&quot;&gt;QVariant TreeModel::&lt;span style=&quot;color: #00eeff;&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt; QModelIndex &amp;amp;index, &lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt; role&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;!index.&lt;span style=&quot;color: #00eeff;&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; QVariant&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;Nous retrouvons le même début de scénario que pour les deux méthodes précédemment analysées, &lt;code&gt;data()&lt;/code&gt; étant public, la validité de &lt;code&gt;index&lt;/code&gt; est éprouvée et un QVariant() invalide est envoyé le cas échéant.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;role != Qt::&lt;span style=&quot;color: #00eeff;&quot;&gt;DisplayRole&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; QVariant&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;Dans cette démo, la vue ne sollicitera que le texte pour son affichage, et donc, tous les rôles autre que &lt;code&gt;Qt::DisplayRole&lt;/code&gt; sont écartés. Pour se faire, un &lt;code&gt;QVariant()&lt;/code&gt; invalide est renvoyé et signifie à l'appelant qu'il fait ce qu'il veut: pour un &lt;code&gt;QTreeView&lt;/code&gt;, ça sera par exemple d'afficher la couleur de fond par défaut du composant dans le cas du &lt;code&gt;Qt::BackgroundRole&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;TreeItem *item = static_cast&amp;lt;TreeItem*&amp;gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;index.&lt;span style=&quot;color: #00eeff;&quot;&gt;internalPointer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; item-&amp;gt;data&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;index.&lt;span style=&quot;color: #00eeff;&quot;&gt;column&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Nous avons besoin de retrouver l'élément correspondant à l'index, puis de renvoyer la donnée correspondant à son numéro de colonne.
La méthode &lt;code&gt;data()&lt;/code&gt; renvoie un &lt;code&gt;QVariant&lt;/code&gt; et nous voyons ici l'utilité sémantique d'avoir stocké une liste de &lt;code&gt;QVariant&lt;/code&gt; au sein du &lt;code&gt;TreeItem&lt;/code&gt; plutôt qu'une liste de &lt;code&gt;QString&lt;/code&gt;, même si en l'occurrence, le renvoi d'un &lt;code&gt;QString&lt;/code&gt; aurait été possible grace à la construction implicite du C++.&lt;/p&gt;


&lt;h5&gt;La méthode &lt;code&gt;rowCount()&lt;/code&gt;&lt;/h5&gt;

&lt;pre class=&quot;cpp&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt; TreeModel::&lt;span style=&quot;color: #00eeff;&quot;&gt;rowCount&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt; QModelIndex &amp;amp;parent&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#123;&lt;/span&gt;
    TreeItem *parentItem;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;parent.&lt;span style=&quot;color: #00eeff;&quot;&gt;column&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &amp;gt; &lt;span style=&quot;color: #0000dd;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000dd;&quot;&gt;0&lt;/span&gt;;&lt;/pre&gt;


&lt;p&gt;Nous avons vu plus haut que le père d'un index a par convention son numéro de colonne égal à 0 dans un cas de hiérarchie classique.
De la même façon, tout index de colonne strictement supérieur à 0 ne possède aucun fils; ce rôle est dévolu à l'index de colonne 0.&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;!parent.&lt;span style=&quot;color: #00eeff;&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        parentItem = rootItem;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;
        parentItem = static_cast&amp;lt;TreeItem*&amp;gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;parent.&lt;span style=&quot;color: #00eeff;&quot;&gt;internalPointer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; parentItem-&amp;gt;childCount&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Comme pour la fonction &lt;code&gt;data()&lt;/code&gt;, il nous faut extraire le &lt;code&gt;TreeItem&lt;/code&gt; correspondant à l'index &lt;code&gt;parent&lt;/code&gt;.
L'appel de &lt;code&gt;rowCount()&lt;/code&gt; avec un index invalide signifie que l'utilisateur souhaite le nombre de noeuds racines, dans ce cas, &lt;code&gt;rootItem&lt;/code&gt; jouera le rôle de l'élément père.
Le nombre d'enfants de l'élément père est alors renvoyé.&lt;/p&gt;


&lt;h5&gt;La méthode &lt;code&gt;columnCount()&lt;/code&gt;&lt;/h5&gt;

&lt;pre class=&quot;cpp&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt; TreeModel::&lt;span style=&quot;color: #00eeff;&quot;&gt;columnCount&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt; QModelIndex &amp;amp;parent&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;parent.&lt;span style=&quot;color: #00eeff;&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; static_cast&amp;lt;TreeItem*&amp;gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;parent.&lt;span style=&quot;color: #00eeff;&quot;&gt;internalPointer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;-&amp;gt;columnCount&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; rootItem-&amp;gt;columnCount&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Elle est similaire à la méthode &lt;code&gt;rowCount()&lt;/code&gt; si ce n'est une difficulté en moins puisque que l'on peut se contenter de renvoyer directement le nombre de colonnes de l'élément attaché à l'index.&lt;/p&gt;


&lt;h5&gt;Les méthodes &lt;code&gt;flags()&lt;/code&gt; et &lt;code&gt;headerData()&lt;/code&gt;&lt;/h5&gt;

&lt;pre class=&quot;cpp&quot;&gt;Qt::&lt;span style=&quot;color: #00eeff;&quot;&gt;ItemFlags&lt;/span&gt; TreeModel::&lt;span style=&quot;color: #00eeff;&quot;&gt;flags&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt; QModelIndex &amp;amp;index&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;!index.&lt;span style=&quot;color: #00eeff;&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000dd;&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; Qt::&lt;span style=&quot;color: #00eeff;&quot;&gt;ItemIsEnabled&lt;/span&gt; | Qt::&lt;span style=&quot;color: #00eeff;&quot;&gt;ItemIsSelectable&lt;/span&gt;;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;C'est dans cette fonction que nous allons définir finement le comportement du modèle.
Nous lui précisons ici que nous souhaitons pouvoir intéragir avec l'index en paramètre (&lt;code&gt;Qt::ItemIsEnabled&lt;/code&gt;), ainsi que le sélectionner (&lt;code&gt;Qt::ItemIsSelectable&lt;/code&gt;).&lt;/p&gt;

&lt;pre class=&quot;cpp&quot;&gt;QVariant TreeModel::&lt;span style=&quot;color: #00eeff;&quot;&gt;headerData&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt; section, Qt::&lt;span style=&quot;color: #00eeff;&quot;&gt;Orientation&lt;/span&gt; orientation,
                               &lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt; role&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;const&lt;/span&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;orientation == Qt::&lt;span style=&quot;color: #00eeff;&quot;&gt;Horizontal&lt;/span&gt; &amp;amp;&amp;amp; role == Qt::&lt;span style=&quot;color: #00eeff;&quot;&gt;DisplayRole&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; rootItem-&amp;gt;data&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;section&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; QVariant&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span style=&quot;color: #000000;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;headerData()&lt;/code&gt; est similaire à la fonction &lt;code&gt;data()&lt;/code&gt; si ce n'est qu'elle concerne uniquement les entêtes des lignes et colonnes. Pour notre exemple, seule l'entête des colonnes est affichée et nous utilisons donc à cette fin les valeurs de &lt;code&gt;rootItem&lt;/code&gt; uniquement dans le cas où l'orientation est &lt;code&gt;Qt::Horizontal&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;


&lt;p&gt;Pour des raisons de simplicité, j'ai jugé utile de limiter ce tutoriel à l'analyse d'un exemple simple et en lecture seule et de nombreux aspects de la manipulation des modèles/vue n'y sont pas abordés.
Par exemple, lorsqu'on veut modifier les données internes, comment avertir le modèle -et donc la vue- que les données ont changées&amp;nbsp;? Comment rendre le modèle éditable; doit-on utiliser les méthodes d'insertions et de suppression du modèle ou un système alternatif&amp;nbsp;? L'édition des données est trop basique, je voudrais la changer, comment faire&amp;nbsp;? Comment construire un système de recherche au sein d'un modèle&amp;nbsp;? Comment gérer les types Mime ainsi que le drag'n'drop&amp;nbsp;?
Ces questions seront abordées dans un tutoriel plus avancé.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://doc.qtfr.org/post/2007/12/16/#rev-pnote-171-1&quot; id=&quot;pnote-171-1&quot;&gt;1&lt;/a&gt;] Si les valeurs renvoyées par &lt;code&gt;row()&lt;/code&gt;, &lt;code&gt;column()&lt;/code&gt; et &lt;code&gt;model()&lt;/code&gt; appartiennent bien en interne au &lt;code&gt;QModelIndex&lt;/code&gt; par le biais de champs privés, le champ &lt;code&gt;parent()&lt;/code&gt; est en revanche une invocation directe de la méthode virtuelle pure &lt;code&gt;parent()&lt;/code&gt; du modèle de l'index. Ceci peut mettre en lumière le rôle de la fonction &lt;code&gt;parent()&lt;/code&gt; du modèle et son implication.&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;http://doc.qtfr.org/post/2007/12/16/#rev-pnote-171-2&quot; id=&quot;pnote-171-2&quot;&gt;2&lt;/a&gt;] Il existe un constructeur du &lt;code&gt;QModelIndex&lt;/code&gt; qui accepte à peu près les mêmes paramètres que &lt;code&gt;createIndex()&lt;/code&gt; et qui aurait pu prendre sa place mais pour des raisons d'intégrité et de cohérence (pour ne jamais avoir d'index sans modèle référent), ce constructeur est privé; le seul moyen de créer un index valide est de passer par le modèle et donc par une des déclinaisons de &lt;code&gt;createIndex()&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
</description>
    
    
    
          <comments>http://doc.qtfr.org/post/2007/12/16/Creation-dun-modele-hierarchique-simple-base-sur-QAbstractItemModel#comment-form</comments>
      <wfw:comment>http://doc.qtfr.org/post/2007/12/16/Creation-dun-modele-hierarchique-simple-base-sur-QAbstractItemModel#comment-form</wfw:comment>
      <wfw:commentRss>http://doc.qtfr.org/feed/rss2/comments/171</wfw:commentRss>
      </item>
    
</channel>
</rss>