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

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

PyQt Python Discussion :

trouver le parent d'un widget dans une multitude de layout


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 28
    Par défaut trouver le parent d'un widget dans une multitude de layout
    bonjour a tous,
    Je poste ce billet car je suis perdu malgré toutes mes recherches je ne trouve pas comment faire. je souhaiterai faire une petite interface de sondage avec une question et un bouton radio a valider ou pas. Mais quand je clique sur le buttonradio je n'arrive pas a trouver le bon parent pour associer l'état a la question.L'interface est simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     
    from PyQt5.Qtcore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
     
    class Test_fenetre(Qwidget):
        def __init__(self):
            super().__init__()
            self.lay_gen=QVBoxLayout(self)
            self.traitement_dataset_excel()
            self.ui_questionnaire()
            self.show()
     
        def traitement_dataset_excel(self):
            #ici je récupérè les données d'un fichier excel et je manipule une colonne df['thématique'] et une colonne['question']
            #je passe sur la déclaration qui n'apporte rien pour votre compréhension
     
        def etat_checkbox(self):
            #Ici je test le certains attributs suite a l'activation d'un checkbox
            print (f"parent du checkbox: {self.sender().parent().layout()}") #ça me donne la QVBoxLayout() qui contient le QHBoxLayout qui contient le QCheckBox
            print (f"autre parent: {self.sender().parent()}") #ca me donne le QGroupBox contenu dans le QVBoxLayout(self.lay_questionnaire)
     
        def ui_questionnaire(self):
            #ici je limite l'itération pour que ce soit plus rapide a comprendre et plus visible.Dans mon interface je pose un QScrollArea pour pouvoir voir toutes les questions classées dans chaque thématique
            for index in range(2):
                self.lay_questionnaire=QVBoxLayout()
                self.group=QGroupBox(str(index))
     
                #Ici aussi je limite l’itération a 2 questions pour plus de facilité
                for indey in range(2):
                    self.lab=QLabel("question_"+str(indey))
                   #Je crée un conteneur de QCheckBox pour donner une note(1 à 5) à la question 
                   self.hlay_question=QHBoxLayout()
     
                   #Je crée les QCheckBox dynamiquement et normalement selon le nombre de questions que j'ai a poser
                   for indexy in range(3):
                       self.note=QCheckBox(str(indexy)):
                       self.note.clicked.connect(self.etat_checkbox)
                       self.hlay_question.addWidget(self.note)
     
                   #Intégration de la question et du QHBoxLayout de QCheckBox dans le QVBoxLayout
                   self.lay_questionnaire.addWidget(self.lab)
                   self.lay_questionnaire.addLayout(self.hlay_question)
     
                #Intégration dans QVBoxLayout général
                self.group.setlayout(self.lay_questionnaire)
                self.lay_gen.addWidget(self.group)
     
    app=QApllication([])
    appli=Test_fenetre()
    app.exec_()
    L'idée c'est au fur et a mesure de l'activation d'un checbox, de valoriser un simple fichier txt comme étant une sauvegarde de l'état du questionnaire,au cas ou ça cracherait. Le problème est que je n'arrive pas a récupérer le parent du qcheckbox,ie le QHBoxLayout conteneur, donc je ne peux pas associer la question à un état True/False. J'arrive a récupérer les QHBoxLayout en passant par self.sender().parent().layout().children() qui me donne une liste des QHBoxLayout, mais impossible de facilement récupérer la question,dans un QLabel positionné au dessus, qui est associée au qcheckbox. J'ai l'intuition qu'il y a une méthode builtin pour faire ça mais je n'y arrive pas. Après j'ai réglé le problème avec une usine a gaz où je numérote les questions et les checkbox par setObjectName et ainsi par slicing je me débrouille pour l'association. Ça marche mais c'est totalement inélégant.

    J'en appelle à la commu car je suis débutant et que je ne trouve pas la réponse.
    Merci pour votre patience et votre aide

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Juin 2018
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2018
    Messages : 29
    Par défaut
    Petite remarque,

    Partager son code, montrer ce que l'on a fait,, c'est bien, encore faudrait t'il qu'il soit fonctionnel ou faire le maximum pour s'en approcher.
    Soit à minima corriger les fautes de frappes.

    self.lay_questioonaire => self.lay_questionnaire
    Qtcore => QtCore
    QApllication => QApplication
    ...
    Ca serait plus sympa non? Et ca ne donne pas envie à un éventuel aidant de débugger... Bref!

    Donc, voici ma réponse, non testée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.note.clicked.connect(self.func)
    doit renvoyer l'état du bouton :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def func(self, state):
    ...
    Sinon, vous avez défini un attribut self.note,
    vous pouvez vous en servir:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    state = self.note.isChecked()
    Ou utiliser un

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 28
    Par défaut
    bonjour,
    oui désolé y a des coquilles que j'ai pas vu malgré la vérification.Par contre je n'ai pas la fin de votre commentaire en bas de page.

    Je vous remercie pour vous être penché dessus mais mon problème n'est pas de vérifier l'état, ça ça fonctionne comme vous l'avez codez en effet. Mon problème est que comme je crée l'interface dynamiquement je ne peux y accéder par le nom du widget simplement mais plutôt par la référence. Du coup j'essaie de récupérer la référence du layout parent pour pouvoir indexer le label qui contient la question et l'associer au qcheckbox clické. Et la ça marche pas car le qcheckbox.parent().layout() me donne le layout parent du layout qui contient les qcheckbox.

    J'ai trouvé une solution inélégante en numérotant par compteurs, les questions et les checkbox avec un décalage de +2, ce qui fait qu'en diminuant l'index du qcheckbox de -1 je récupère le bon qlabel donc la bonne question.

    Merci pour votre participation
    Cordialement

  4. #4
    Membre éclairé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Juin 2018
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2018
    Messages : 29
    Par défaut
    Ok, j'ai compris ce que vous souhaitez faire

    Oui, c'est possible, mais cela nécessite de bien comprendre la structure de l'interface que vous avez créé : quel widget est dans quelle boite...
    plus les boites seront simples et organisées, plus il sera facile de s'y retrouver, peut-être qu’un peu de papier et un crayon peut aider à ce stade...

    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    frame = QFrame()
    question_layout = QVBoxLayout()
     
    label=QLabel("question_"+str(question_nb))
    question_Cb = QCheckBox(str(question_nb))
    question_Cb.clicked.connect(self.etat_checkbox)
     
    question_layout.addWidget(label)
    question_layout.addWidget(question_Cb)
     
    frame.setLayout(question_layout)
    Permet de retouver une structure relativement simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    self.sender().parent().children()
    [<PyQt5.QtWidgets.QVBoxLayout object at 0x7f5489af41f0>, <PyQt5.QtWidgets.QLabel object at 0x7f5489af4280>, <PyQt5.QtWidgets.QCheckBox object at 0x7f5489af4310>]
    Sinon, vous pouvez définir un nouvel attribut au checkbutton:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    question_Cb = QCheckBox(str(question_nb))
    question_Cb.mon_texte = "ma question"
    ou isoler le label et le bouton dans une classe qui s'occuperait de gérer l'événement et de récupérer la question

    Voilà, pour commencer, nettoyez un peu votre code:
    - pas besoin des "self." si vous ne voulez pas garder une références des objets (encore plus si vous écraser l'attribut dans une boucle)
    - nommez explicitement vos variables, objets, boites, cela vous aidera à vous y retrouver
    - vérifiez l'utilité de chacune des trois boucles

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 28
    Par défaut
    bonjour,
    Merci a nouveau de vous être penché sur le sujet.Mais au final je comprends que mon problème n'a pas de solution.Mes QCheckBox sont contenus dans une QHBoxLayout par thématique, qui sont contenus dans une QVBoxLayout et dès que je fais self.sender().parent().layout() j'obtiens la QVBoxLayout et pas le conteneur,QHBoxLayout, de mes QCheckBox. On dirait que c'est câblé comme ça et puis c'est marre.

    J'ai fait le choix conceptuel de créer une interface dynamiquement,en récupérant mes questions de sondage depuis un fichier excel dans un dataset.Si j'ajoute des questions je n'ai pas a me re-palucher tous les objets d'interface en dur.Voila pourquoi ces widgets n'ont pas de nom propres et que je les atteins par leur référence ou celui du parent. J'ai trouvé une solution,peu élégante,en synchronisant un compteur pour le label des questions et chaque QHBoxLayout qui contient les QCheckBox. Ainsi par décalage j'ai la bonne question au QCheckBox clické. Mon objectif était de sauvegarder la validation des QCheckBox en temps réel dans un fichier csv. C'est fait et ça marche.

    Merci pour votre aide
    Cordialement

  6. #6
    Membre éclairé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Juin 2018
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2018
    Messages : 29
    Par défaut
    Si je vous dis que c'est possible!?

    PyQt rassemble les widgets tel que vous le décrivez dans votre code, si vous ne comprenez pas la structure obtenue, c'est que vous ne comprenez pas la structure que vous avez écrit.
    Dessinez un arbre sur le papier...

    Quand vous faites mon_layout.addWidget, vous ajouter un enfant à la liste d'enfants du widget et non un enfant à mon_layout.
    Ce layout (ajouté avec setLayout) fait aussi parti de la liste des enfants du widget.

    Si les boites sont assez petites (c-à-d ne contiennent pas trop d'objets), un test sur le type de l'enfant peut permettre de retrouver ce que l'on cherche. Dis autrement, si la liste mon_widget.children() contient une seule QCheckBox, c'est plus facile de s'y retrouver que s'il y a en 50.

    Voici un code qui exploite les méthodes détaillées en #4
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
     
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
     
     
    class BoitesImbriquees(QScrollArea):
        def __init__(self):
            super().__init__()
     
            window = QWidget()
            window_layout = QVBoxLayout()
            self.ui_questionnaire(window_layout)
            window.setLayout(window_layout)
     
            self.setWidget(window)
            self.show()
     
        def etat_checkbox(self):
     
            Cb = self.sender()
     
            print('\nCase cochée !!!!!!!!!!!!!!!\n')
     
            print("Cb = self.sender()\n")
     
            print("En inspectant la structure :")
            print("[w.text() for w in Cb.parent().parent().parent().children() if isinstance(w, QLabel)][0] :", [w.text() for w in  Cb.parent().parent().parent().children() if isinstance(w, QLabel)][0])
            print("[w.title() for w in Cb.parent().parent().parent().children() if isinstance(w, QGroupBoxl)][0] :", [w.title() for w in  Cb.parent().parent().parent().children() if isinstance(w, QGroupBox)][0])
            print("[w.text() for w in Cb.parent().children() if isinstance(w, QLabel)][0] :", [w.text() for w in Cb.parent().children() if isinstance(w, QLabel)][0])
            print("[Cb.text() :", Cb.text())
     
            print("\nEn donnant un nouvel attribut :")
            print(f"Cb.section_name : {Cb.section_name}")
            print(f"Cb.sub_section_name : {Cb.sub_section_name}")
            print(f"Cb.question_text : {Cb.question_text}")
     
        def ui_questionnaire(self, parent):
     
            from itertools import islice, count, cycle, product
            from string import ascii_lowercase as a_lc, ascii_uppercase as a_uc
     
            # Un générateur ésotérique de sections!
            SECTIONS = a_uc[:4]
            sub_section_gen = (islice(count(), i, i+3) for i in count(0,3))
            question_gen = (islice((''.join(x) for x in product(a_lc, a_lc)), i, i+3) for i in count(0, 3))
     
            for s in SECTIONS:
     
                SOUS_SECTIONS = next(sub_section_gen)
     
                section_frame = QFrame()
                section_label = QLabel(f"section {s}")
                section_layout = QVBoxLayout()
                section_layout.addWidget(section_label)
     
                for ss in SOUS_SECTIONS:
     
                    QUESTIONS = next(question_gen)
     
                    sub_section_box = QGroupBox(f"Sous Section {ss}")
                    sub_section_layout = QHBoxLayout()
     
                    for q in QUESTIONS:
     
                        question_frame = QFrame()
                        question_layout = QHBoxLayout()
     
     
                        question_label=QLabel(f"Question {q}")
                        question_Cb = QCheckBox(str(q))
                        question_Cb.clicked.connect(self.etat_checkbox)
     
                        question_Cb.section_name = s
                        question_Cb.sub_section_name = ss
                        question_Cb.question_text = q
     
                        question_layout.addWidget(question_label)
                        question_layout.addWidget(question_Cb)
     
     
                        question_frame.setLayout(question_layout)
     
                        sub_section_layout.addWidget(question_frame)
     
                    sub_section_box.setLayout(sub_section_layout)
                    section_layout.addWidget(sub_section_box)
     
                section_frame.setLayout(section_layout)
     
                parent.addWidget(section_frame)
     
     
    app=QApplication([])
    appli=BoitesImbriquees()
    app.exec_()

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par estrasse Voir le message
    J'ai fait le choix conceptuel de créer une interface dynamiquement,en récupérant mes questions de sondage depuis un fichier excel dans un dataset.Si j'ajoute des questions je n'ai pas a me re-palucher tous les objets d'interface en dur.Voila pourquoi ces widgets n'ont pas de nom propres et que je les atteins par leur référence ou celui du parent.
    Pas de souci. Te suffit de créer une widget de ta conception associée à une et une seule question (exemple QQuestion) puis ensuite à chaque question lue dans le fichier tu génère une "QQuestion" que tu ajoutes dans une liste. Et en même temps tu places cette QQuestion dans un QVBoxLayout lui-même mis dans un QScrollArea (ce qui te permet d'avoir un ascenseur quand le nombre de questions dépasse la taille de l'écran).
    Ensuite pour récupérer quelle widget a été cochée il y a plusieurs possibilités. Tu peux rajouter dans ton QQuestion un slot spécial qui renvoie son identifiant quand sa (parce que lui il n'en a qu'une seule) CheckBox est cochée et quand tu récupères cet identifiant tu regardes dans la liste de QQuestion à qui il appartient. Ou bien tu insères dans ton QQuestion un signal spécial que tu peux associer à un QSignalMapper pour récupérer automatiquement quelle QQuestion a été cochée. Mais comme le dit Daguhh, cela ne peut se faire que si tu décomposes proprement ton problème et sa solution

    Citation Envoyé par estrasse Voir le message
    J'ai trouvé une solution,peu élégante,en synchronisant un compteur pour le label des questions et chaque QHBoxLayout qui contient les QCheckBox. Ainsi par décalage j'ai la bonne question au QCheckBox clické. Mon objectif était de sauvegarder la validation des QCheckBox en temps réel dans un fichier csv. C'est fait et ça marche.
    Oui, mais comme tu le dis "peu élégant" dans le sens où ça reste du bricolage.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Réponses: 9
    Dernier message: 09/11/2019, 22h13
  2. Positionner un WidGet dans une table
    Par sorry60 dans le forum GTK+ avec C & C++
    Réponses: 7
    Dernier message: 05/11/2005, 19h22
  3. comment modifier les widgets dans une fenètre??
    Par afrikha dans le forum GTK+ avec C & C++
    Réponses: 6
    Dernier message: 14/10/2005, 14h48
  4. Réponses: 8
    Dernier message: 08/06/2004, 01h29

Partager

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