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 :

Signal quand on quitte un QTableWidget


Sujet :

PyQt Python

  1. #1
    Membre habitué
    Homme Profil pro
    Géomaticien
    Inscrit en
    Octobre 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 12
    Par défaut Signal quand on quitte un QTableWidget
    Bonjour à tous,

    Je débute avec PyQt, je suis en train de faire une interface en PyQT sous forme de formulaire pour remplir une Base de données.

    Je bloque sur un point :

    A un endroit j'ai un Qtablewidget avec 2 boutons : un pour ajouter un élément, un autre pour supprimer l'élément sélectionné. Du coup à la base mon bouton "supprimer" est désactivé par défault et s'active quand je sélectionne une ligne de la table (j'utilise le Signal itemSelectionChanged).

    Maintenant j'aimerais désactiver le bouton quand je "sors" du Qtablewidget vers un autre Widget du formulaire mais je n'y arrive pas :

    - je n'ai pas trouvé de signal à faire émettre par QTableWidget

    - j'ai pensé à émettre un signal quand je clique sur un autre widget (QLineEdit par exemple) mais je ne trouve pas non plus : j'ai cru comprendre qu'il faut réimplémenter un mouseClicEvent, mais en bon débutant que je suis, je n'y suis pas encore parvenu et surtout, je me demande si c'est la meilleure méthode sachant que je devrais recréer le même signal pour chaque widget de mon formulaire ce qui me semble alourdir le code pour peu.

    Qu'en pensez-vous?

    Merci d'avance,

    Maxime

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    On peut utiliser les méthodes focusOutEvent et focusInEvent qui sont automatiquement appelées lorsque le QTableWidget respectivement perd et récupère le focus. Il faut surcharger ces méthodes pour faire ce qu'on veut faire.

    Ce sont bien ici les méthodes de QTableWidget dont on a besoin, ce qui logiquement nécessite de sous-classer QTableWidget. C'est facile à faire, sauf si on veut absolument utiliser QDesigner pour dessiner la fenêtre.

    Dans ce dernier cas, il y a une astuce: il s'agit de rediriger les méthodes focusOutEvent et focusInEvent de la table sur celle de la fenêtre. Il faut alors pouvoir tester au début de ces méthodes si la table est concernée ou pas par l'évènement.

    Voilà un petit code exemple:

    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
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    # Python 2.7
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Fenetre(QtGui.QWidget):
     
        # =======================================================================
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
            self.resize(800,600)
     
            self.tableWidget = QtGui.QTableWidget(self)
            self.nbrow, self.nbcol = 7, 7
            self.tableWidget.setRowCount(self.nbrow)
            self.tableWidget.setColumnCount(self.nbcol)
     
            self.tableWidget.focusInEvent = self.focusInEvent
            self.tableWidget.focusOutEvent = self.focusOutEvent
     
            self.bouton1 = QtGui.QPushButton(self)
            self.bouton2 = QtGui.QPushButton(self)
     
            posit = QtGui.QGridLayout()
            posit.addWidget(self.tableWidget, 0, 0)
            posit.addWidget(self.bouton1, 1, 0)
            posit.addWidget(self.bouton2, 2, 0)
            self.setLayout(posit)
     
            self.tableWidget.setFocus()
            self.tablefocus = True
            self.tableWidget.setCurrentCell(0, 0)
     
        # =======================================================================
        def focusInEvent(self, event):
     
            if self.tableWidget.hasFocus():
                print u"la table prend le focus!"
                self.tablefocus = True
                event.accept()
            else:
                QtGui.QWidget.focusInEvent(self, event)
     
        # =======================================================================
        def focusOutEvent(self, event):
     
            if self.tablefocus:
                print u"la table perd le focus!"
                self.tablefocus = False
                event.accept()
            else:
                QtGui.QWidget.focusOutEvent(self, event)
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Il faut lancer ça dans une console ou dans un outil de développement à cause du print.

    Il y a une table et 2 boutons. Quand la table prend le focus ou le perd, les messages s'affichent. Par contre, quand on clique alternativement sur l'un et l'autre des boutons, il n'y a aucun message parce que la table n'est pas concernée.

  3. #3
    Membre habitué
    Homme Profil pro
    Géomaticien
    Inscrit en
    Octobre 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 12
    Par défaut
    Merci beaucoup pour la réponse, je teste ça et ferai un retour. Je ne l'ai pas précisé mais effectivement je veux utiliser QDesigner.

    Bonne après-midi,

    Maxime

  4. #4
    Membre habitué
    Homme Profil pro
    Géomaticien
    Inscrit en
    Octobre 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 12
    Par défaut
    Super ça marche! Par contre je suis confronté à un autre soucis du coup : si je clique sur le boutton "supprimer" la table perd le focus, du coup je ne peux plus cliquer sur supprimer

  5. #5
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Si j'ai bien compris (ce qui n'est pas sûr), il suffit de redonner le focus à la table, dans la méthode de traitement du clic du bouton "supprimer".

  6. #6
    Membre habitué
    Homme Profil pro
    Géomaticien
    Inscrit en
    Octobre 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 12
    Par défaut
    Merci beaucoup de prendre le temps de me répondre en tout cas!

    En fait je veux que l'utilisateur ait la possibilité de cliquer sur "supprimer" (pour supprimer une entrée de la table) uniquement quand il a préalablement sélectionné une ligne.

    Là j'ai 2 petits soucis :

    - la table prend le focus au démarrage par défaut même quand j'enlève les lignes suivantes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            self.Table.setFocus()
            self.tablefocus=True
            self.Table.setCurrentCell(0,0)
    - Quand je sélectionne une ligne de ma table, le bouton "supprimer" est bien actif mais quand j'essaye de cliquer dessus, il ne l'est plus puisque la table perd le focus et que je lui ai demandé d'être inactif quand il perd le focus.

    Voici mon code sur lequel je fais mes tests :


    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
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    # -*- coding: cp1252 -*-
     
    from PyQt4.QtCore import SIGNAL, SLOT, Qt, QEvent
    from PyQt4.QtGui import QApplication, QWidget, QLineEdit, QPushButton, QHBoxLayout, QTableWidget,QTableWidgetItem, QLabel, QAbstractItemView
    import sys
     
    class Form(QWidget):
        def __init__(self, parent=None):
            super(Form, self).__init__(parent)
            self.Layout=QHBoxLayout(self)     
            self.Table=QTableWidget(self)
            self.Table.focusInEvent=self.focusInEvent
            self.Table.focusOutEvent=self.focusOutEvent
    #        self.Table.setFocus()
    #        self.tablefocus=True
    #        self.Table.setCurrentCell(0,0)
            self.remplirTable()
            self.Boutton=QPushButton("Ajouter une notification")
            self.Boutton.connect(self.Boutton, SIGNAL("clicked()"), self.slotAction)
            self.Boutton2=QPushButton("Supprimer une notification")
            self.Boutton2.setEnabled(False)
            self.Boutton2.connect(self.Boutton2, SIGNAL("clicked()"), self.slotAction2)
            self.LineEdit=QLineEdit()
            self.LineEdit2=QLineEdit()
            self.Layout.addWidget(self.Table)
            self.Layout.addWidget(self.Boutton)
            self.Layout.addWidget(self.Boutton2)
            self.Layout.addWidget(self.LineEdit)
            self.Layout.addWidget(self.LineEdit2)
     
        def remplirTable(self):
            self.Table.clear()
            self.Table.setRowCount(len(Liste))
            self.Table.setColumnCount(3)
            self.Table.setAlternatingRowColors(True)
            self.Table.setHorizontalHeaderLabels(["Num", "Date", "Destinataire"])
            self.Table.verticalHeader().hide()
            self.Table.setEditTriggers(QAbstractItemView.NoEditTriggers)
            self.Table.setSelectionMode(QAbstractItemView.SingleSelection)
            self.Table.setSelectionBehavior(QAbstractItemView.SelectRows)
            for r,row in enumerate(Liste):
                for c,column in enumerate(row):
                    self.Item=QTableWidgetItem(column)
                    self.Table.setItem(r,c,self.Item)
            self.Table.resizeColumnsToContents()
     
        def slotAction(self):
            self.notif=Notif()
            self.notif.show()
     
        def slotAction2(self):
            self.Table.setCurrentCell(self.Table.currentRow(),0)
            Suppr=self.Table.currentItem().text()
            for i,n in enumerate(Liste):
                if Liste[i][0]==Suppr:
                    Liste.pop(i)
            self.remplirTable()
     
     
        def focusInEvent(self,event):
            if self.Table.hasFocus():
                print u"la table prend le focus"
                self.tablefocus=True
                self.Boutton2.setEnabled(True)
                event.accept()
    #        else:
    #            QWidget.focusInEvent(self,event)
     
        def focusOutEvent(self,event):
            if self.tablefocus:
                print u"la table perd le focus"
                self.tablefocus=False
                self.Boutton2.setEnabled(False)
                event.accept()
    #        else:
    #            QWidget.focusOutEvent(self,event)
     
    class Notif(QWidget):
        def __init__(self, parent=None):
            super(Notif, self).__init__(parent)
            self.NotifLayout=QHBoxLayout(self)
            self.labelNotif1=QLabel(self)
            self.labelNotif1.setText("Date :")
            self.lineEdit_Notif1=QLineEdit(self)
            self.labelNotif2=QLabel(self)
            self.labelNotif2.setText("Destinataire :")
            self.lineEdit_Notif2=QLineEdit(self)
            self.BouttonNotif=QPushButton("Ok")
            self.BouttonNotif.connect(self.BouttonNotif, SIGNAL("clicked()"),self.slotAction)
            self.NotifLayout.addWidget(self.labelNotif1)
            self.NotifLayout.addWidget(self.lineEdit_Notif1)
            self.NotifLayout.addWidget(self.labelNotif2)
            self.NotifLayout.addWidget(self.lineEdit_Notif2)      
            self.NotifLayout.addWidget(self.BouttonNotif)
     
        def slotAction(self):
            self.Date=self.lineEdit_Notif1.text()
            self.Destinataire=self.lineEdit_Notif2.text()
            self.ListeID=[]
            try:
                for n in Liste:
                    self.ListeID.append(int(n[0]))
                self.maxListeID=max(self.ListeID)+1
            except:
                self.maxListeID=1
            Liste.append([unicode(self.maxListeID),self.Date,self.Destinataire])
            form.remplirTable()
            form.notif.close()
     
     
    if __name__== "__main__" :
        App=QApplication(sys.argv)
        Liste=[["1","2013-01-07","M. Prout"],["2","2012-12-05","Mme Prout"],["3","2012-10-12","Mr Caca"]]
        form=Form()
        form.show()
        App.exec_()

  7. #7
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Effectivement, je n'avais pas tout compris.

    - Pour le 1er point, sur quel widget de la fenêtre devrait aller le focus au démarrage?

    - Pour le 2e point, essaie avec ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        def focusOutEvent(self,event):
            if self.tablefocus:
                print u"la table perd le focus"
                self.tablefocus=False
                if not self.Boutton2.hasFocus():
                    self.Boutton2.setEnabled(False)
                event.accept()
    Principe: quand la table perd le focus, le bouton "supprimer" (bouttons2) est désactivé, sauf quand c'est lui qui a récupéré le focus!

    Mais attention, tel que c'est codé, si tu cliques 2 fois de suite sur le bouton, cela génère une erreur.

  8. #8
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 304
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 304
    Par défaut
    Salut,

    En sousclassant la table, j'obtiens exactement le comportement demandé.

    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
     
    # -*- coding: utf-8 -*-
     
    from PyQt4 import QtCore, QtGui
     
    class Main(QtGui.QMainWindow):
        def __init__(self):
            super(Main, self).__init__()
            self.resize(350, 278)
            self.widget = QtGui.QWidget(self)
            self.gridLayout = QtGui.QGridLayout(self.widget)
            self.verticalLayout = QtGui.QVBoxLayout()
            self.table = TableWidget(self, self.widget)
            self.verticalLayout.addWidget(self.table)
            self.horizontalLayout = QtGui.QHBoxLayout()
            self.button = QtGui.QPushButton(self.widget)
            self.button.setText('Button 1')
            self.horizontalLayout.addWidget(self.button)
            spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, 
                                            QtGui.QSizePolicy.Minimum)
            self.horizontalLayout.addItem(spacerItem)
            self.button_2 = QtGui.QPushButton(self.widget)
            self.button_2.setText('Button 2')
            self.horizontalLayout.addWidget(self.button_2)
            self.verticalLayout.addLayout(self.horizontalLayout)
            self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
            self.setCentralWidget(self.widget)
            self.show()
            self.table.populate_table()
            self.button.setEnabled(False)
            self.button.clicked.connect(self.table.remove_row)
     
     
    class TableWidget(QtGui.QTableWidget):
        def __init__(self, main, parent=None):
            super(TableWidget, self).__init__(parent)
            self.main = main
            self.setColumnCount(3)
            self.setRowCount(3)
            self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
            self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
            self.itemSelectionChanged.connect(self.on_selection_changed)
     
        def populate_table(self):
            people = [('Jean', 'Rome', '125478'), ('Paul', 'Paris', '65478'),
                        ('Pierre', 'Zurich', '954287')]
            for r, row in enumerate(people):
                for c, column in enumerate(row):
                    self.item = QtGui.QTableWidgetItem(column)
                    self.setItem(r, c, self.item)
     
        def on_selection_changed(self):
            self.main.button.setEnabled(len(self.selectedItems()))
     
        def remove_row(self):
            self.clearSelection()
     
        def focusOutEvent(self, event):
            self.clearSelection()
     
    if __name__ == "__main__":
        import sys
        app = QtGui.QApplication(sys.argv)
        ui = Main()
        sys.exit(app.exec_())
    Donc le bouton 1 est activé uniquement lors d'une sélection dans la table et désactivé quand la table perd le focus, en cliquant sur le bouton 2 par exemple.

  9. #9
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour VinsS,

    Oui, la solution du sous-classement est certainement la meilleure solution et la plus naturelle. Elle n'avait été mise de côté que parce que c'est plus compliqué à utiliser avec Qt Designer.

    D'un autre côté, il est inévitable d'apprendre un jour ou l'autre à créer de nouveaux composants et à les utiliser dans Qt Designer. Puisque j'en avais besoin, j'ai défini une gamme de travail (http://python.jpvweb.com/mesrecettes...uveaux_widgets) que j'applique couramment: ça marche très bien. Mais on ne peut pas dire que ce soit simple...

  10. #10
    Membre habitué
    Homme Profil pro
    Géomaticien
    Inscrit en
    Octobre 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 12
    Par défaut
    Merci pour toutes vos pistes. Ca me permet d'y voir plus clair!

    En effet la solution du sous-classement semble la plus simple mais effectivement je veux pouvoir utiliser QtDesigner et ne pas modifier le fichier py qui en sort afin de pouvoir modifier mon formulaire sous QtDesigner très rapidement.

    Je vais étudier la solution de Tyrtamos pour ajouter de nouveaux composants dans Qt Designer.

    Sinon je peux peut-être utiliser Qt Designer mais laisser un espace vide à l'emplacement des mes QTableWidget pour les définir "à la main" en les "sous-classant" ?

    Bonne journée,

    Maxime

  11. #11
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par Bescu Voir le message
    Sinon je peux peut-être utiliser Qt Designer mais laisser un espace vide à l'emplacement des mes QTableWidget pour les définir "à la main" en les "sous-classant" ?
    Oui, tu devrais pouvoir dessiner ta fenêtre avec Qt Designer en utilisant le QTableWidget normal, et lui substituer dans ton code ton "QTableWidget_perso" avec la même géométrie (.geometry/.setGeometry). Vérifie que ça marche: je n'ai jamais essayé ça.

Discussions similaires

  1. [c#]Destructeur, problème quand je quitte de programme
    Par skysee dans le forum Windows Forms
    Réponses: 28
    Dernier message: 01/06/2008, 23h10
  2. Comprendre demande d'enregistrement quand on quitte
    Par Lucas Panny dans le forum Visual C++
    Réponses: 4
    Dernier message: 06/12/2007, 09h55
  3. Réponses: 4
    Dernier message: 24/01/2007, 15h59
  4. Réponses: 2
    Dernier message: 08/08/2006, 22h17
  5. Réponses: 1
    Dernier message: 16/05/2004, 17h56

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