Partage
  • Partager sur Facebook
  • Partager sur Twitter

Construction d'un QVector contenant des *QWidget

Pointeurs sur de QWidgets numérotés

Sujet résolu
    20 octobre 2019 à 14:58:48

    Bonjour, je suis débutant en C++ et sur Qt mais pas en programmation, dans mon jeune temps j’ai appris à programmer en basic, Fortran et VB5 mais ça date un peu et les ordinateurs n’étaient pas ce qu’ils sont maintenant. J’ai acheté le livre « Programmez avec le langage C++ » d’openclassrooms que je recommande sans modération, avec ça et la doc sur internet on peut apprendre correctement.

    Dans mon ancien boulot (je ne travaillais pas du tout dans l’informatique, je suis maintenant retraité) j’ai fait un programme en VB5 que je voudrais « moderniser » en C++ avec Qt. J’avance bien mais là je coince sur un problème de programmation répétitive que je voudrais raccourcir. Je gère des widgets avec de nombreux champs de saisie, la saisie et la récupération des données dans ces champs se fait avec des boucle for à l’aide d’un Qvector de pointeur comme par exemple :

    QVector<QDoubleSpinBox*>m_Pk

    Le compteur de la boucle for en lien avec l’index du Qvector me permet de choisir les champs concernés, l'index correspondant au numéro qui se trouve à la fin du nom.

    Pour l’instant je construis mes Qvector de la manière suivante :

    m_Pk.append(ui->doubleSpinBox_Pk_00);

    m_Pk.append(ui->doubleSpinBox_Pk_01);

    m_Pk.append(ui->doubleSpinBox_Pk_02);

    m_Pk.append(ui->doubleSpinBox_Pk_03);

    m_Pk.append(ui->doubleSpinBox_Pk_04);

    etc…..

    Il y a beaucoup de champs (j’ai une bonne vingtaine de noms de champs, chacun allant de 0 à 50) alors ça devient très vite fastidieux, comme il y a une construction logique des noms des champs (nom_00, nom_01, nom_02, etc…), je pense qu’il est possible de construire les Qvector de pointeurs à l’aide de boucles for mais, malgrés mes recherches sur internet, je ne trouve pas comment faire.

    Je sais construire le nom des champs en incorporant le compteur d’une boucle for dans un Qstring mais ensuite comment peut-on se servir de ce Qstring pour extraire le pointeur sur le champ concerné et le mettre dans le Qvector ?

    Merci de votre aide et bonne journée

    BRAHMA89

    • Partager sur Facebook
    • Partager sur Twitter
      20 octobre 2019 à 19:53:31

      Il faudrait mieux expliquer ton probleme, peut etre donner du code. Pas sur de comprendre.

      En tout cas, si tu voudrais faire un truc du genre :

      for (int i = 0; i < 50; ++i)
          nom = "doubleSpinBox_Pk_" + i;

      Ce n'est pas possible. Tes variables crees avec le designer ont un nom.

      • Partager sur Facebook
      • Partager sur Twitter
        20 octobre 2019 à 22:29:31

        Bonjour gbdivers,

        Merci de t’intéresser à ma question. Je ne cherche pas à nommer les QDoubleSpinBox où les QSpinBox (ce que j’appelle les champs dans ma première intervention), ils ont été nommés lorsque j’ai crée mon QWidget avec le Designer et j’ai mis un numéro à la fin de leur nom. Je cherche à construire des QVector de pointeurs sur ces champs qui me permettraient de les utiliser dans des boucles For. J’explique plus précisément :

        Soient 51 QdoubleSpinBox nommés (Pk signifie Point kilométrique) :

        doubleSpinBox_Pk_00

        doubleSpinBox_Pk_01

        etc … jusqu’à doubleSpinBox_Pk_50

        Soient 51 QspinBox nommés (numPt signifie numéro du point):

        spinBox_numPt_00

        spinBox_numPt_01

        etc… jusqu’à spinBox_numPt_50

        J’en reste là mais il y a d’autres données telles que l’espacement entre les points, l’altitude réelle, l’altitude théorique, etc…

        Le point dont le numéro correspond à spinBox_numPt_00 est au kilomètre indiqué par doubleSpinBox_Pk_00.

        En fonction de la zone que j’analyse je peux avoir des centaines de points, par exemple un point tous les 5 mètres sur plusieurs kilomètres.

        Quand, par exemple, j’affiche mes numéros de points je veux pouvoir le faire dans une boucle, je donne le numéro du premier point et ensuite j’incrémente cette valeur pour les points suivants.

        Comme je n’affiche que 51 points je fais défiler mes points à l’aide d’une QScrollBar en modifiant le numéro du premier point affiché pour pouvoir balayer toutes la zone.

        Le moyen le plus facile, me semble-t-il, est de construire des QVector de pointeurs qui pointent sur les widget concernés, par exemple :


        QVector<QDoubleSpinBox*> m_Pk

        m_Pk[0] pointant sur le widget nommé doubleSpinBox_Pk_00, etc..

        QVector<QspinBox*> m_numPt

        m_numPt[0] pointant sur le widget nommé spinBox_numPt_00

        Cela me permet de travailler dans des boucles For à l’aide du compteur des boucles et de l’index des QVector.

        Je sais construire les QVector en saisissant à chaque fois le nom du widget :

        m_Pk.append(ui->doubleSpinBox_Pk_00);

        m_Pk.append(ui->doubleSpinBox_Pk_01);

        m_Pk.append(ui->doubleSpinBox_Pk_02);

        m_Pk.append(ui->doubleSpinBox_Pk_03);

        m_Pk.append(ui->doubleSpinBox_Pk_04);

        etc…..

        et ça marche mais je ne trouve pas ça pratique, ça fait des lignes de programme à n’en plus finir (20 noms de champs avec 51 déclinaisons chacun) alors qu’il devrait être possible de construire les QVectors de pointeurs dans des boucles du genre :

        for (int i(0); i < 51; i++) {
            m_Pk.append(maFonctionPk(i));
            m_numPt.append(maFonctionNumPt(i);
        }

        Ce que je n’arrive pas à trouver c’est s’il existe une fonction du genre maFonctionPk(i) où comment la créer (où toute autre méthode) qui permettrait d’extraire le pointeur du widget en s’appuyant sur son nom et le numéro qui le compose.

        J’ai penser qu’il fallait passer par un QString car il est possible de recréer le nom du widget dans une boucle sous forme de QString…

        …mais après il faut pouvoir se servir de ce nom sous forme de Qstring pour extraire le pointeur du widget et c’est là que je ne trouve pas de solution.

        Je suis en train de me rendre compte que si on trouve des fonctions du genre maFonctionEcrirePk(i) et maFonctionLirePk(i) et qui permettrait d’écrire où de lire dans mes QdoubleSpinBox on peut éventuellement directement les utiliser dans le programme et ainsi éviter de passer par des QVector de pointeur…

        Pas évident à expliquer.

        Merci à vous

        • Partager sur Facebook
        • Partager sur Twitter
          20 octobre 2019 à 23:03:34

          Cela n'est pas possible (*) tout simplement parce que les noms que tu donnes dans le designer et en C++ n'existent plus apres la compilation. Donc ca n'a pas de sens de vouloir acceder a une variable via son nom.

          A partir du moment ou tu vas creer tes objets avec le designer, tu ne peux y acceder que par leur nom. Donc tu es bloque. Si tu veux faire ca, il faut que tu crees tes widgets via le C++. 

          (*) il doit etre possible de passer via les meta objects et la fonction children, en donnant un nom aux objets, mais c'est une approche galere, c'est plus simple de creer les widgets en C++.

          • Partager sur Facebook
          • Partager sur Twitter
            21 octobre 2019 à 20:12:48

            Bonjour gbdivers,

            Je vais arrêter de chercher sur internet, j'y ai déjà passé pas mal de temps et ça devient inutile car comme tu me le dis ce n'est pas possible avec la méthode que je souhaitais utiliser. Je vais, comme tu me le conseilles, construire mes widget directement dans C++ comme ça je pourrai déclarer directement mes QVector de pointeur en "instanciant" mes widget. Ça va me faire un bon exercice car je n'ai que peu pratiqué les widget sans passé par le designer. Dans son cours C++ openclassroom indique qu'il faut savoir construire des widget "à la main" car Designer n'est pas la solution à tous les problèmes... preuve en est... c'est quand même une aide très puissante et une partie de mes widget resteront la création du Designer.

            Merci encore et bon clavier

            • Partager sur Facebook
            • Partager sur Twitter
              21 octobre 2019 à 21:56:30

              Une solution est de creer un widget personnalisé, qui ne va contenir que tes 50 spinbox, puis d'utiliser ce widget dans le design, pour creer le reste de l'UI comme tu faisais avant. De cette maniere, tu as les avantages des 2 approches.
              • Partager sur Facebook
              • Partager sur Twitter
                21 octobre 2019 à 22:46:29

                Si comme tu l'écris, tes widgets sont déjà créés avec le bon nom, uic a déjà nommé ces objets automatiquement avec setObjectName (il suffit de regarder le fichier ui_xxx.h généré), donc oui, tu peux les récupérer simplement dans une boucle:

                for (int i(0); i < 51; i++) {
                    QString objectName = QString("doubleSpinBox_Pk_%1").arg(i, /* fill */ 2, /* base */ 10, /* fillChar */ QChar('0'));
                    QDoubleSpinBox* spinbox =  findChild<QDoubleSpinBox*>(objectName);    
                    m_Pk.append(spinbox);
                }
                
                

                Ou tu peux faire l'inverse: récupérer l'ensemble des QDoubleSpinBox avec QWidget::findChildren<QDoubleSpinBox*>, puis extraire le nom et le numéro en parsant la propriété objectName (mais il faudra les insérer d'abord dans un QMap, avec l'index avant de les remettre dans l'ordre dans le QVector).

                const char* const Prefix_SpinBoxPk = "doubleSpinBox_Pk_";
                ...
                
                    QMap<int, QDoubleSpinBox*> Pk_tmp_map;
                    for(QDoubleSpinBox *spinbox : findChildren<QDoubleSpinBox*>()) {
                        QString objectName = spinbox->objectName();
                        if(objectName.startsWith(Prefix_SpinBoxPk)) {
                            int index = objectName.mid(qstrlen(Prefix_SpinBoxPk)).toInt();
                            Pk_tmp_map[index] = spinbox;
                        }
                    }
                    m_Pk.append(Pk_tmp_map.values().toVector());




                -
                Edité par alexisdm 22 octobre 2019 à 11:40:06

                • Partager sur Facebook
                • Partager sur Twitter
                  22 octobre 2019 à 1:46:31

                  Salut,

                  alexisdm a écrit:

                  Si comme tu l'écris, tes widgets sont déjà créés avec le bon nom, uic a déjà nommé ces objets automatiquement avec setObjectName (il suffit de regarder le fichier ui_xxx.h généré), donc oui, tu peux les récupérer simplement dans une boucle:

                  for (int i(0); i < 51; i++) {
                      QString objectName = QString("doubleSpinBox_Pk_%1").arg(i, /* fill */ 2, /* base */ 10, /* fillChar */ QChar('0'));
                      QDoubleSpinBox* spinbox =  findChild<QDoubleSpinBox*>(objectName);    
                      m_Pk.append(spinbox);
                  }
                  
                  

                  A ceci près que la manipulation de chaines de caractères est sans doute la manipulation en mémoire qui prend le plus de temps :

                  • Tu vas, de toutes manières, devoir convertir un entier en chaine de caractères, ce qui se fait (même si tu n'en as pas conscience) au travers d'une boucle et d'une allocation dynamique de la mémoire à chaque passage dans la boucle
                  • après avoir converti ton entier en chaine de caractères, tu devras la concaténer à la chaine de caractères d'origine, ce qui provoquera une nouvelle allocation dynamique de la mémoire
                  • Enfin, la comparaison entre deux chaines de caractères est elle-même particulièrement lente, surtout lorsque les deux chaines ont la même longueur et que leur base (comprends: les XXX premiers caractères qui les composent) sont identiques

                  Attention, je ne dis absolument pas que les solutions que tu proposes ne sont pas correctes!  Je dis juste qu'elles sont de nature à plomber littéralement les performances si tu te retrouve à les utiliser trop souvent.

                  Je sais bien que les performances ne sont généralement pas vraiment le problème de l'interface graphique, qu'une demi seconde d'attente ne gène généralement pas plus l'utilisateur que cela.

                  Mais il faut te dire que, si tu te retrouve à avoir cinquante spinbox sur une même fenêtre, c'est parce que:

                  • tu t'attend à ce que l'utilisateur modifie cinquante valeurs
                  • tu t'attend donc à devoir récupérer cinquante valeurs très régulièrement
                  • ces cinquantes valeurs seront nécessaires pour un grand nombre de manipulations des données métiers sous-jacentes.

                  Si tu ne devais accéder à tes cinquante spinbox qu'une fois ou deux, je ne verrais aucune objection à l'utilisation de ta méthode.  Mais, étant donné l'usage que tu risque de faire des valeurs qu'elles représentent, tu risques de devoir y recourir à  tout bout de champs, et souvent de manière répétée.

                  Il vaut donc mieux essayer de faire en sorte que ces spinboxes soient accessibles "le plus rapidement possible" ;)

                  Dans de telles conditions, rien ne vaut la création d'interfaces de manière programmée ;)

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                    22 octobre 2019 à 2:15:14

                    C'est la solution dont je parlais en note, dans mes précédents messages. En plus des critiques formulées par koala01, l'utilisation des meta objets de Qt, via la fonction findChild, imlique aussi une perte de performance (parcours récursif des enfants, dynamique cast, comparaison des types, etc)
                    • Partager sur Facebook
                    • Partager sur Twitter
                      22 octobre 2019 à 16:37:33

                      Salut à tous,

                      A vous lire je m’aperçois que ma 1ère idée de passer par un QString n'est pas impossible mais vous faites intervenir un autre paramètre dont je ne me souciais pas du tout jusqu'à maintenant: la vitesse d'exécution. Dans mon cas par exemple je peux être amené à gérer des centaines de points voir quelques milliers. Pour faire défiler tout ça à l'écran, comme je l'ai dit plus haut, je me sers d'une QScrollBar qui définit le 1er point et ensuite tous les autres sont recalculés, si je veux un maximun de fluidité quand je manipule la QScrollBar j'ai intérêt à me soucier du temps d'accès à tous mes widgets et ne pas venir le plomber en manipulant des QString.

                      Je découvre les pointeurs et ça fait un peu peur à cause de la fuite de mémoire. Par exemple lorsque je vais instancier mes widgets (de base ou personnalisés) je vais le faire avec des new, donc allocation de mémoire sur le tas. Après relecture du cours d'openclassroom, si j'ai bien compris, lorsqu'on détruit un widget parent, tous les widgets enfants sont également détruits automatiquement par Qt, même s'ils sont instanciés dynamiquement, donc je n'aurais pas besoin de faire de delete...


                      Est-ce que vous confirmez ?

                      A+


                      • Partager sur Facebook
                      • Partager sur Twitter
                        22 octobre 2019 à 17:17:28

                        La meilleure méthode aurait été d'utiliser un QTableView pour afficher 50 fois les 20 champs différents et de les stocker dans une classe de modèle ou une base de données. Ou éventuellement de créer un widgets personnalisé avec les 20 champs, pour les faire afficher par un QListView à l'aide de QDataWidgetMapper comme s'il s'agissait d'un layout, mais avec l'avantage que tu n'as pas à manipuler les widgets pour faire les calculs puisque toutes les données seraient déjà dans des tableaux.

                        gbdivers a écrit:

                        C'est la solution dont je parlais en note, dans mes précédents messages. En plus des critiques formulées par koala01, l'utilisation des meta objets de Qt, via la fonction findChild, imlique aussi une perte de performance (parcours récursif des enfants, dynamique cast, comparaison des types, etc)

                        Je proposais juste ça parce que tu as indiqué plusieurs fois, et c'est ce que BRAHMA89 a fini par retenir, que c'était impossible, ou compliqué, sachant que la partie inutilement répétitive, à savoir la création de l'interface dans le designer, avait déjà été faite.

                        Je suis d'accord que findChild n'est pas très "scalable" (même si pour les 50x20 widgets dont il est question, ça ne semble pas être si perceptible, ça multiplie par 8 le temps de création et ça ne fait  que ~200ms en tout sur mon PC), mais la méthode proposée avec findChildren ne met à plat la liste qu'une seule fois, et même avec les comparaisons de chaînes ou de types, ça ne semble représenter que moins de 5% de temps en plus par rapport à la création des widgets eux-mêmes.

                        koala01 a écrit:

                        Si tu ne devais accéder à tes cinquante spinbox qu'une fois ou deux, je ne verrais aucune objection à l'utilisation de ta méthode.  

                        Ca n'est exécuté qu'une seule fois, à la création de la fenêtre, justement pour accéder plus facilement aux widgets déjà créés dans le designer, donc pas d'objection ? 

                        koala01 a écrit:

                        A ceci près que la manipulation de chaines de caractères est sans doute la manipulation en mémoire qui prend le plus de temps :

                        Qt fait déjà des comparaisons de chaînes à la création de toutes les fenêtres créées dans le designer, pour tenter de connecter automatiquement tous les slots connus à tous les widgets connus (QWidget::connectSlotsByName), ou pour appliquer les feuilles de styles, ou pire encore, si tu utilises QML.

                        Le problème de la méthode avec findChild, ce ne sont pas les chaînes, mais le fait que ce soit en O(n²) sur le nombre de widgets de la fenêtre (avec n > 1000, ce que je n'avais pas vu au départ).

                        BRAHMA89 a écrit:

                        Pour faire défiler tout ça à l'écran, comme je l'ai dit plus haut, je me sers d'une QScrollBar qui définit le 1er point et ensuite tous les autres sont recalculés, si je veux un maximum de fluidité quand je manipule la QScrollBar j'ai intérêt à me soucier du temps d'accès à tous mes widgets et ne pas venir le plomber en manipulant des QString.

                        A moins que tu utilises les QString extrêmement souvent, et pas une seule fois à l'ouverture de la fenêtre, ça ne va pas impacter l'affichage. Si tu dois mettre à jour beaucoup de widgets à la fois, tu peux désactiver les mises à jour de l'affichage le temps des modifications et les réactiver après, avec QWidget::setUpdatesEnabled sur le widget parent. Mais il faut déjà voir si tu as des problèmes de performances avant de vouloir optimiser quoi que ce soit.

                        lorsqu'on détruit un widget parent, tous les widgets enfants sont également détruits automatiquement par Qt, même s'ils sont instanciés dynamiquement, donc je n'aurais pas besoin de faire de delete...

                        Oui, c'est bien ça.

                        -
                        Edité par alexisdm 22 octobre 2019 à 17:22:09

                        • Partager sur Facebook
                        • Partager sur Twitter
                          22 octobre 2019 à 18:07:43

                          alexisdm a écrit:

                          Ca n'est exécuté qu'une seule fois, à la création de la fenêtre, justement pour accéder plus facilement aux widgets déjà créés dans le designer, donc pas d'objection ?

                          Héhé... non... Enfin si j'ai une objection: après avoir placé les widgets dans une collection quelconque pour pouvoir y accéder plus facilement, il faudra bien que tu accèdes à la valeurs que ces widgets représente pour pouvoir passer à la suite des événements...

                          Cela signifie que tu devras définir dynamiquement le nom du widget qui t'intéresse (avec les conversions qui s'imposent), puis que tu devras accédé à l'élément nommé dans ta collection. Bref, tu vas te retrouver à renouveler un nombre incalculable de fois l'ensemble du processus, et sans doute à pleins d'endroits différents dans ton code (même si rien ne t'empêche de créer une fonction qui s'occupe de te renvoyer le widget souhaité ;) )

                          alexisdm a écrit:

                          Qt fait déjà des comparaisons de chaînes à la création de toutes les fenêtres créées dans le designer, pour tenter de connecter automatiquement tous les slots connus à tous les widgets connus (QWidget::connectSlotsByName), ou pour appliquer les feuilles de styles, ou pire encore, si tu utilises QML.

                          Je suis tout à fait d'accord avec toi : Qt fait déjà des comparaisons de chaines à la création de toutes les fenêtre dessinées dans le designer.  Mais ce processus est destiné à n'être effectué qu'une seule et unique fois, à la création de la fenêtre, à l'initialisation de l'application.

                          Le processus que tu propose est un processus auquel l'utilisateur va faire appel tout au long de l'exécution, ce qui commence à faire beaucoup ;)

                          alexisdm a écrit:

                          A moins que tu utilises les QString extrêmement souvent, et pas une seule fois à l'ouverture de la fenêtre, ça ne va pas impacter l'affichage. Si tu dois mettre à jour beaucoup de widgets à la fois, tu peux désactiver les mises à jour de l'affichage le temps des modifications et les réactiver après, avec QWidget::setUpdatesEnabled sur le widget parent. Mais il faut déjà voir si tu as des problèmes de performances avant de vouloir optimiser quoi que ce soit.

                           Mais justement: à partir du moment où le seul moyen d'accédere à un widget passe par le nom qui a été donné à l'instance du widget en question, tu peux t'attendre à utiliser ce nom à peu près n'importe quand dans ton application, et donc, à devoir générer le nom du wiget qui t'intéresse particulièrement souvent ;)

                          Si, d'une manière ou d'une autre, tu t'arranges pour placer les widgets non pas dans une map, mais bien dans un simple tableau, en veillant à ce que l'indice dans le tableau corresponde à la logique de nommage de tes widgets (par exemple : indice = numéro du widget -1), tu évites tous les problèmes liés aux comparaisons de chaines, car tu peux alors utiliser une boucle simple prenant la forme de

                          for(size_t i =0; i<nombre_widgets; ++i){
                              /* accède à la valeur du widget dont le nom correspond
                               * à widget_i+1
                               */
                              auto value = tableau_widgets[1]->value();
                          }

                          alexisdm a écrit:

                          Mais il faut déjà voir si tu as des problèmes de performances avant de vouloir optimiser quoi que ce soit.

                          Je suis tout à fait d'accord avec toi : l'optimisation prématurée est la mère de tous les maux.

                          Mais il s'agit de comprendre ce que l'on entend par "optimisation prématurée":

                          Il y a optimisation prématurée lorsque l'on nous sort une formule de "derrière les fagots" sans avoir le début d'une preuve qu'elle permettra -- effectivement -- de gagner de performances.

                          Le choix d'une collection (tableau / map, pile ou file, et autres), d'un algorithme ou d'un critère de tri / de sélection adapté ne fait clairement pas partie de cette catégorie:  Ce choix participe à suivre le conseil de Albert Einstein:

                          Rendez vos développement aussi complexes que nécessaires, mais guère plus

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                            22 octobre 2019 à 21:52:36

                            koala01 a écrit:

                            Héhé... non... Enfin si j'ai une objection: après avoir placé les widgets dans une collection quelconque pour pouvoir y accéder plus facilement, il faudra bien que tu accèdes à la valeurs que ces widgets représente pour pouvoir passer à la suite des événements...

                            Cela signifie que tu devras définir dynamiquement le nom du widget qui t'intéresse (avec les conversions qui s'imposent), puis que tu devras accédé à l'élément nommé dans ta collection. Bref, tu vas te retrouver à renouveler un nombre incalculable de fois l'ensemble du processus, et sans doute à pleins d'endroits différents dans ton code (même si rien ne t'empêche de créer une fonction qui s'occupe de te renvoyer le widget souhaité ;) )

                            Il n'y a aucune raison d'accéder aux noms des widgets une fois qu'ils sont dans les QVectors.

                            En fait d'après ce que j'ai compris, il a 50 lignes de 20 widgets, qui servent à représenter une "fenêtre coulissante" sur un nombre de lignes plus important. Ces widgets sont déjà créés dans le designer, ce qu'il cherche à faire, c'est mettre les pointeurs vers ces widgets dans des QVectors pour pouvoir y accéder.

                            Pour chacune des 20 colonnes, il a une variable différente QVector<QDoubleSpinBox*> ou QVector<QLineEdit*> en fonction du type de données contenu dans cette colonne (il n'a pas précisé les différents types qui pouvaient exister).

                            S'il veut par exemple afficher les lignes 101 à 150, il va dans une boucle avec 20 lignes remplir les valeurs des widgets à partir de 20 autres tableau ou d'un tableau de structure contenant 20 valeur (ce n'est pas précisé non plus) juste comme ça, en supposant que les données se trouvent dans un tableau de structure:

                            int offset = 100;
                            for(int i=0; i < 50; ++i) {
                              m_Pk[i].setValue(donnees[i+offset].pk);
                              m_NumPt[i].setValue(donnees[i+offset].numPt);
                              m_EspPt[i].setValue(donnees[i+offset].espPt);
                              m_AltReel[i].setValue(donnees[i+offset].altReel);
                              m_AltTheo[i].setValue(donnees[i+offset].altTheo);
                              /// ... au moins 15 autres lignes ...
                            }

                            Avec m_Pk, m_NumPt, m_EspPt,, m_AltReel, m_AltTheo qui seraient les QVector<QDoubleSpinBox*>.

                            Le code que j'avais proposé sert juste à automatiser le remplissage des tableaux de pointeurs de widgets, à aucun moment dans le reste de son code, il n'a besoin du nom des widgets.

                            Je n'avais pas tout à fait compris ça au début, sinon j'aurais proposé l'utilisation du QTableView et un modèle dès le début. Par contre, je ne comprends pas ce que toi tu as compris :) 

                            • Partager sur Facebook
                            • Partager sur Twitter
                              23 octobre 2019 à 3:06:45

                              alexisdm a écrit:

                              Il n'y a aucune raison d'accéder aux noms des widgets une fois qu'ils sont dans les QVectors.

                              C'est encore à voir, en fonction de la manière dont ils sont placés dans ce vecteur.

                              Et puis, toi tu parlais d'une map.  Or, quoi qu'il en soit, si un arbre binaire de recherche présente de nombreux avantages, l'utilisation d'un tableau est bien souvent une meilleure alternative ;)

                              Alors, il est possible que j'ai mal compris ce que tu voulais faire, et même que j'aie mal compris ce que Braham voulait faire, mais, persoonnellement, j'avais compris qu'il voulait accéder à ces widget au travers de leurs nom, indépendamment de la manière dont ils étaient stockés ;)

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                23 octobre 2019 à 10:45:47

                                Bonjour à tous,

                                Vous avez été très productifs, vos écrits sont intéressants pour moi dans le sens où j'apprends le C++ et Qt même s'ils vont au delà de ma question initiale.

                                koala01 a écrit:

                                alexisdm a écrit:

                                Il n'y a aucune raison d'accéder aux noms des widgets une fois qu'ils sont dans les QVectors.

                                C'est encore à voir, en fonction de la manière dont ils sont placés dans ce vecteur.

                                Et puis, toi tu parlais d'une map.  Or, quoi qu'il en soit, si un arbre binaire de recherche présente de nombreux avantages, l'utilisation d'un tableau est bien souvent une meilleure alternative ;)

                                Alors, il est possible que j'ai mal compris ce que tu voulais faire, et même que j'aie mal compris ce que Braham voulait faire, mais, persoonnellement, j'avais compris qu'il voulait accéder à ces widget au travers de leurs nom, indépendamment de la manière dont ils étaient stockés ;)

                                C'est exactement ce que je voulais faire, accéder à mes widgets au travers de leur nom parce que je n'avais pas envisagé de faire autrement. Certainement parce que c'est comme ça que j'avais fait en VB5 et que je m'enfermais dans mes habitudes. A vous lire, j'aborde le problème différemment et ceci pour 2 raisons :

                                • Si mes widgets sont pointés dans un QVector de pointeurs je n'ai, à aucun moment, besoin de leur noms
                                • Je n'ai pas forcément besoin de tous mes widgets, en fait j'en avais mis 51 pour pouvoir m'adapter aux différentes définitions possibles de l'écran de l'utilisateur
                                Je suis maintenant convaincu de l'intérêt de programmer mes widgets "numérotés" sans passer par le designer, de cette manière je les pointe directement dans un QVector de pointeurs sans me soucier de leur nom et en plus je n'en créé que le nombre nécessaire en fonction de la définition de l'écran de l'utilisateur.
                                Je n'envisage pas de gérer mes données sous forme de base de données car dans mes séries de données (colonnes de widgets numérotés) il y en a qui sont saisies par l'utilisateur (relevés terrain) et d'autres qui sont calculées et que je ne souhaite pas sauvegarder. Je souhaite que certains calculs (pas tous) se fassent en même temps que la saisie afin de détecter, par exemple, une erreur de saisie ou une erreur dans la définition du profil.

                                alexisdm a écrit:

                                S'il veut par exemple afficher les lignes 101 à 150, il va dans une boucle avec 20 lignes remplir les valeurs des widgets à partir de 20 autres tableau ou d'un tableau de structure contenant 20 valeur (ce n'est pas précisé non plus) juste comme ça, en supposant que les données se trouvent dans un tableau de structure:

                                int offset = 100;
                                for(int i=0; i < 50; ++i) {
                                  m_Pk[i].setValue(donnees[i+offset].pk);
                                  m_NumPt[i].setValue(donnees[i+offset].numPt);
                                  m_EspPt[i].setValue(donnees[i+offset].espPt);
                                  m_AltReel[i].setValue(donnees[i+offset].altReel);
                                  m_AltTheo[i].setValue(donnees[i+offset].altTheo);
                                  /// ... au moins 15 autres lignes ...
                                }

                                Avec m_Pk, m_NumPt, m_EspPt,, m_AltReel, m_AltTheo qui seraient les QVector<QDoubleSpinBox*>.

                                Effectivement je sauvegarde mes données dans des tableaux de structure (des QVector car je ne sais pas à l'avance le nombre de points qu'il y aura dans la zone étudiée). Quand je fais défiler mes données à l'écran à l'aide de la  QScrollBar il faut que je sauvegarde en live les données modifiées par l'utilisateur avant de les perdre en passant à l'affichage suivant.

                                Pour vous faire un peu comprendre ce que je fais, j'analyse la géométrie d'une voie ferrée pour en détecter les défauts et pouvoir les corriger. Pour se faire on met des repères numérotés sur le rail et on fait des mesures géométriques (cordeau, niveau de géomètre...). Les mesures faites vont permettre de comparer le profil relevé au profil théorique et d'en déduire les défauts. En gros le profil théorique est une succession de parties rectilignes, de courbes, de raccordements paraboliques, de raccordements circulaires... Tout ça dans les 2 sens, position de la voie verticalement (nivellement = altitudes) et horizontalement (dressage de la voie).

                                Pour simplifier l'organisation des données elles sont divisées en 2 catégories: l'analyse verticale (nivellement) et l'analyse horizontale (dressage). Pour chaque catégorie j'ai 2 formulaires principaux, un qui permet de définir le profil théorique et l'autre pour les relevés terrain. Il faut définir le profil théorique avant de saisir les données terrain car les widgets calculés en ont besoin pour justement être calculés.

                                Après il faudra que je passe à la programmation graphique pour avoir un visuel des défauts, ça a été fait partiellement en VB5 mais je n'en suis pas encore là en C++. En voyant ce que l'on peut faire graphiquement avec Qt je pense pouvoir faire des chose vraiment sympa mais j'ai du boulot d'apprentissage en perspective.

                                Il faut que je m'informe de la règle pour clore une demande (demande résolue) parce qu'un sujet en amenant un autre on peut discuter longtemps surtout que je suis beaucoup en demande.

                                Merci à tous.

                                Bon je retourne à mes confitures : de la gelée de coings, mon cognassier en est couvert.

                                -
                                Edité par BRAHMA89 23 octobre 2019 à 11:05:05

                                • Partager sur Facebook
                                • Partager sur Twitter

                                Construction d'un QVector contenant des *QWidget

                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                • Editeur
                                • Markdown