Bon, nous allons donc de "gratter un peu le vernis" pour t'aider à comprendre...
Qt (et attention, il y a une différence entre Qt et QT: QT c'est ce que l'on utilise pour désigner QuickTime, qui par chance, a été abandonné depuis longtemps. Qt, c'est le framework que tu utilises ) est un framework, à l'origine, développé pour permettre la mise en oeuvre d'IHM (Interfaces Homme / Machine, aussi connues sous le nom d'"interface graphique").
Un framework, c'est un ensemble de fonctionnalités qui sont mises à ta disposition, mais que tu dois apprendre à utiliser de manière correcte. Car, si tu ne l'utilises pas de manière correcte, tu n'arriveras à rien.
Le fait est que Qt est un framework pour le moins... envahissant: Si tu n'y prends pas garde, tu te retrouve très rapidement dans une situation dans laquelle Qt va s'imposer à tous les niveaux de ton application. Et ca, c'est pas la meilleure des choses qui soient.
C'est même une situation particulièrement dommage, parce que Qt a justement été développé pour permettre la mise en oeuvre d'une architecture de type MVC (pour Model, View, controler) ou, pour être vraiment précis, de type MVD (pour Model, View, Delegate).
Le principe de ces architectures est de créer une séparation claire et précise entre les données qui font partie de ton "corps de métier" (c'est ce que l'on appelle "le modèle") d'une part, ce qui permet de fournir -- par exemple à l'utilisateur -- une représentation de ces donnée (c'est ce que l'on appelle "la vue") d'autre part et, pour une troisième part ce qui permet à la vue manipuler les données métier (c'est ce que l'on appelle "le controleur" ou "le délégué").
On s'est en effet rendu compte depuis près de vingt ans que, si l'on ne séparait pas ces trois éléments, nous finissions rapidement avec un projet monolithique, difficile à faire évoluer et, surtout, impossible à adapter -- le cas échéant -- à d'autres technologies, mais que si on sépare clairement le modèle des deux autres éléments (car il y a une certaine dépendance entre les délégués et la vue, étant donné que la vue est ce qui récupèrera les différentes entrées occasionnées par l'utilisateur), les choses deviennent tout de suite beaucoup plus simples.
Note que ce que l'on appelle "la vue" regroupe une gamme de domaines particulièrement large, parce que nous pourrions définir n'importe quel moyen permettant à ton application de transmettre une représentation sous quelque forme que ce soit des données dont elle dispose comme faisant partie de la vue.
C'est la raison pour laquelle Qt est composé d'autant de modules, car, si tu veux envoyer des données sur le réseau (par exemple), l'ensemble des données que tu veux transmettre peut être considéré comme une vue.
L'idée est donc de faire en sorte que le modèle ne dépende absolument pas du framework que tu utilise pour créer ton interface graphique. Comment Hé bien, en (très) gros, en te limitant au fonctionnalités fournies par la bibliothèque standard du langage que tu utilises. En C++, ce sera (pour simplifier à l'extrême) tout ce qui se trouve dans l'espace de noms std.
Tu n'as, en effet, absolument pas besoin de plus que ce qui se trouve dans l'espace de noms std pour pouvoir lire un fichier et en extraire les coordonnées GPS qui s'y trouvent. Car, après tout, ce que tu veux obtenir, c'est "simplement" une chaine de caractères (qui pourra être représentée sous la forme d'une std::string) et deux double (le type primitif double que le compilateur connait sans même avoir besoin d'inclure le moindre fichier d'en-tête).
Mieux encore, tu n'as absolument aucun besoin de créer une classe, dont les données qui la composent seraient dans l'accessibilité privée et qui exposerait quelques services "qui vont bien": Tu peux créer ce que l'on appelle un POD (pour Plain Old Data), ou, si tu préfères, une bonne vieille structure telle que l'on en créait déjà en C.
Ainsi, tu pourrais tout à fait créer une structure proche deEt comme tu voudras manipuler plusieurs coordonnées GPS, il serait sans doute utile de créer la notion de "conteneur de coordonnées GPS".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 struct GpsCoordinate{ std::string code; double longitude; double latitude; };
Cette notion peut être une classe, car, on se rend compte que l'on attendra de sa part "un certain nombre" de services, mais que celui qui va l'utiliser se fout royalement de "comment elle s'y prend" pour les rendre.
Bien sur, nous pourrions décider de représenter cette notions par un "simple" alias de type(comme using GpsCoordinateHolder = std::vector<GpsCoordinate>;, mais la classe std::vector expose énormément de services, et il n'y en a qu'une toute petite partie qui nous intéresse. Or, le principe de création des différentes notions que l'on développe est de
L'utilisation d'un alias de type rendra très facile le fait d'utiliser notre notion de manière incorrecte. Il est donc préférable de fournir une classe qui n'exposera que les services dont on a vraiment besoin, et ce, même si elle utilise la classe std::vector en interne (mais ca, celui qui va utiliser la classe en question s'en fout royalement!). Elle pourrait prendre une forme proche defaire en sorte que notre classe soit facile à utiliser correctement et difficile à utiliser de manière incorrecte.
Avec cette structure (GpsCoordinate) et cette classe (GpsCoordinateHolder) nous avons les moyens de représenter toutes les données métier que tu as parlé jusqu'à présent. Et il n'en faut pas plus ! Tu n'as aucun besoin de passer par le framework Qt pour représenter tes données métier
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 class GpsCoordinateHolder{ public: /* on veut sans doute pouvoir connaitre le nombre de coordonnées GPS dont on dispose */ size_t size() const{ return datas_.size(); } /* on veut pouvoir accéder EN LECTURE SEULE à une coordonnée GPS particulière */ GpsCoordinate const & operator[](size_t index) const; // je passe l'implémentation ;) /* on veut pouvoir parcourir EN LECTURE SEULE l'ensemble des coordonnées GPS à l'aide d'itérateurs */ using const_iterator = typename std::vector<GpsCoordinate>::const_iterator; const_iterator begin() const{ return datas_.begin(); } const_iterator end() const{ return datas_.end(); } /* on veut pouvoir supprimer TOUTES les coordonnées GPS */ void clear(){ datas_.clear(); } /* et on veut pouvoir charger un ensemble de coordonnées GPS * depuis un fichier quelconque (dont le nom nous est donné */ void loadFromFile(std::string const & filename); // je passe l'implémentation ;) // utilise std::ifstream en interne :D private: std::vector<GpsCoordinate> datas_; };
Enfin, il n'en faut pas plus... en l'état de ce que je sais de ton projet Car nous pourrions envisager de créer une structure permettant de convertir les double que nous avons obtenus en degrés de longitude et de latitude, qui pourrait aussi bien prendre une forme proche deMais bon, ce sera à toi de voir si tu as besoin de cela au niveau de tes données métier, ou si tu peux te contenter des GpsCoordinate
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 struct Degree{ enum Type{ longitude, latitude }; enum Direction{ north, south, east, west }; Degree(double value, Type t):type{t}{/* ... */} Type type; Direction direction; unsigned short degree; unsigned short minutes; unsigned short seconds; unsigned double decimalPart; };
Par contre, ce n'est qu'une fois que tu auras ces données métier que tu pourra commencer à t'inquiéter des différentes représentations qui en sont faites (dans ton interface graphique, par exemple).
L'idée sera alors de créer une (ou sans doute plusieurs) vues dans Qt, qui correspondra (correspondront chacune) à une manière de représenter tes données que tu souhaite proposer à l'utilisateur de ton application et un (ou sans doute plusieurs) "modèle(s) de conversion" (attention, cela n'a rien à voir avec la notion de modèle que l'on retrouve dans MVC, même si le terme est semblable ) qui permetra (qui permettront) de "remplir" cette (ces) vue(s) avec tes données métier.
Enfin, si tu souhaites modifier les données métier (c'est souvent le cas, quand on propose une IHM), tu créera un (ou sans doute plusieurs) "contrôleur(s)" (ou plutôt "délégué(s)") qui s'occupera (qui s'occuperont) de traiter tous les événement susceptibles de provoquer une modification des données générés par la (les) vue(s) et de faire appel aux fonctions exposée par ta partie métier.
En travaillant de la sorte, ta partie métier va rester totalement "agnostique": si, un jour, tu décide de créer une autre application en utilisant un autre framework, tu n'auras qu'à prendre toutes les classes (et structures) "métier", et "tout ce qu'il te restera à faire", c'est de créer tes vues et tes contrôleurs / délégués en utilisant cet autre framework.
Partager