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 :

Widget de correspondance de données [Tutoriel]


Sujet :

PyQt Python

  1. #1
    Membre confirmé

    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 44
    Points : 536
    Points
    536
    Par défaut Widget de correspondance de données
    La classe QDataWidgetMapper, introduite dans Qt 4.2, apporte une interface qui permet d'associer des données à un formulaire. Cette manière d'afficher les données facilite la création d'applications basées sur des registres et permet de modifier l'interface utilisateur avec des outils plus habituels tels que Qt Designer.

    Bien que les items de Qt soient capables d'afficher des informations en grande quantité, de nombreuses applications ont tendance à utiliser les registres et les interfaces en formulaires pour présenter les données de façon simplifiée. Parfois, c'est parce que les utilisateurs y sont plus habitués, parfois parce que c'est une conséquence du stockage des données.

    Cet article est la version Python de Widget de correspondance de données. Les exemples sont réalisés sous Python 3.2 avec PyQt 4.7.

    Widget de correspondance de données

    Voir aussi les Cours et tutoriels pour apprendre Python

  2. #2
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Janvier 2013
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Janvier 2013
    Messages : 19
    Points : 41
    Points
    41
    Par défaut [QtGui] Widget de correspondance de données : fenetre vide
    Je ne parviens pas à faire fonctionner votre exemple.
    J'obtiens une fenêtre vide.
    Il me semble que les widgets ne sont pas positionnés dans la fenêtre, je me trompe ?

    En bas de l'article il y a un lien vers les sources... qui ne fonctionne pas.
    Merci

  3. #3
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Très intéressant, merci!

    Jusqu'à présent, j'utilisais surtout des QTableView pour visualiser et modifier des tables d'une base de données SQL, mais je n'avais rien pour les formulaires.

    [Attention, ce qui suit est en Python 2.7]

    Effectivement, dans l'exemple, il manque le positionnement des widgets dans la fenêtre. Voilà une solution qui donne le bon positionnement:

    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
            # positionnement des widgets dans la fenêtre
            posit = QtGui.QGridLayout()
            # 1ère ligne
            posit.addWidget(self.nameLabel, 0, 0, 1, 1)
            posit.addWidget(self.nameEdit, 0, 1, 1, 2)
            posit.addWidget(self.nextButton, 0, 3, 1, 1)
            # 2e ligne
            posit.addWidget(self.addressLabel, 1, 0, 1, 1)
            posit.addWidget(self.addressEdit, 1, 1, 2, 2)
            posit.addWidget(self.previousButton, 1, 3, 1, 1)
            # 3e ligne
            posit.addWidget(self.ageLabel, 3, 0, 1, 1)
            posit.addWidget(self.ageSpinBox, 3, 1, 1, 2)
            # mise en place
            self.setLayout(posit)
    Pour terminer ce tuto, il serait bien de dire comment on récupère les informations modifiées: names, adresses et ages. Pour afficher ces modifs, j'ai ajouté ceci à la classe (on affiche avec une ctrl-Q):

    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
        # =======================================================================
        def keyPressEvent(self, event):
            if event.key() == QtCore.Qt.Key_Q and (event.modifiers() & QtCore.Qt.ControlModifier):
                nbrow = self.model.rowCount()
                nbcol = self.model.columnCount()
                # récup de la liste names dans la colonne d'indice 0
                names = []
                j = 0
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    names.append(unicode(self.model.data(modelindex).toString()))
                # récup de la liste adresses dans la colonne d'indice 1
                adresses = []
                j = 1
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    data = self.model.data(modelindex).toString()
                    te = QtGui.QTextEdit()
                    te.setHtml(data)
                    adresses.append(unicode(te.toPlainText()))
                # récup de la liste ages dans la colonne d'indice 2
                ages = []
                j = 2
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    ages.append(unicode(self.model.data(modelindex).toString()))
                # affichage
                QtGui.QMessageBox.information(self,
                    u"Etat des variables",
                    unicode(names) + '\n' + unicode(adresses) + '\n' + unicode(ages))
                event.accept()
            else:
                event.ignore()
    Pour récupérer l'adresse (colonne d'indice 1), j'ai eu un problème bizarre: même si je dis que le QTextEdit ne supporte que du texte normal (=> self.addressEdit.setAcceptRichText(False)), les données du modèle me renvoie systématiquement du html. Pour convertir html=>texte, j'ai utilisé un autre QTextEdit: ce n'est peut-être pas élégant, mais ça marche.

    Pour faciliter les essais, voici mon code de test complet, toujours en Python 2.7, mais les modifications à faire sont mineures pour passer en 3.2 (surtout pb unicode):

    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
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    #Python 2.7
     
    import sys, os
     
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Window(QtGui.QWidget):
        """Classe principale"""
     
        #========================================================================
        def __init__(self, parent=None):
            """Constructeur"""
            super(Window, self).__init__(parent)
            self.setWindowTitle(u"Exemple de QDataWidgetMapper")
     
            self.setupModel()
     
            # Nom
            self.nameLabel = QtGui.QLabel(u"Nom:")
            self.nameEdit = QtGui.QLineEdit()
     
            # Adresse        
            self.addressLabel = QtGui.QLabel(u"Adresse:")
            self.addressEdit = QtGui.QTextEdit()
            self.addressEdit.setAcceptRichText(False)
     
            # Âge
            self.ageLabel = QtGui.QLabel(u"Âge:")
            self.ageSpinBox = QtGui.QSpinBox()
     
            # Navigation
            self.nextButton = QtGui.QPushButton(u"Suivant")
            self.previousButton = QtGui.QPushButton(u"Précédent")
     
            # Widget de correspondance
            self.mapper = QtGui.QDataWidgetMapper(self)
            self.mapper.setModel(self.model)
            self.mapper.addMapping(self.nameEdit, 0)
            self.mapper.addMapping(self.addressEdit, 1)
            self.mapper.addMapping(self.ageSpinBox, 2)
     
            #Connexions
            self.connect(self.previousButton, QtCore.SIGNAL("clicked()"), self.mapper, QtCore.SLOT("toPrevious()"))
            self.connect(self.nextButton, QtCore.SIGNAL("clicked()"), self.mapper, QtCore.SLOT("toNext()"))
            self.connect(self.mapper,QtCore.SIGNAL("currentIndexChanged(int)"), self.updateButtons)
     
            self.mapper.toFirst() # Nécessaire au premier lancement 
            self.updateButtons(0) # 
     
            # positionnement des widgets dans la fenêtre
            posit = QtGui.QGridLayout()
            # 1ère ligne
            posit.addWidget(self.nameLabel, 0, 0, 1, 1)
            posit.addWidget(self.nameEdit, 0, 1, 1, 2)
            posit.addWidget(self.nextButton, 0, 3, 1, 1)
            # 2e ligne
            posit.addWidget(self.addressLabel, 1, 0, 1, 1)
            posit.addWidget(self.addressEdit, 1, 1, 2, 2)
            posit.addWidget(self.previousButton, 1, 3, 1, 1)
            # 3e ligne
            posit.addWidget(self.ageLabel, 3, 0, 1, 1)
            posit.addWidget(self.ageSpinBox, 3, 1, 1, 2)
            # mise en place
            self.setLayout(posit)
     
        #========================================================================
        def setupModel(self):
                """Crée le modèle"""
                self.model = QtGui.QStandardItemModel(5, 3, self)
     
                names = [u"Alice", u"Bob", u"Carol", u"Donald", u"Emma"]
                adresses = [u"", u"", u"", u"", u""]
                ages = [u"12", u"25", u"29", u"32", u"41"]
     
                for row in range(0,5):
                    item = QtGui.QStandardItem(names[row])
                    self.model.setItem(row, 0, item)
     
                    item = QtGui.QStandardItem(adresses[row])
                    self.model.setItem(row, 1, item)
     
                    item = QtGui.QStandardItem(ages[row])
                    self.model.setItem(row, 2, item)
     
        #========================================================================
        def updateButtons(self, index):
                """Met à jour l'état des boutons si nécessaire"""
                self.previousButton.setEnabled(index>0)
                self.nextButton.setEnabled(index<self.model.rowCount()-1)
     
        # =======================================================================
        def keyPressEvent(self, event):
            if event.key() == QtCore.Qt.Key_Q and (event.modifiers() & QtCore.Qt.ControlModifier):
                nbrow = self.model.rowCount()
                nbcol = self.model.columnCount()
                # récup de la liste names dans la colonne d'indice 0
                names = []
                j = 0
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    names.append(unicode(self.model.data(modelindex).toString()))
                # récup de la liste adresses dans la colonne d'indice 1
                adresses = []
                j = 1
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    data = self.model.data(modelindex).toString()
                    te = QtGui.QTextEdit()
                    te.setHtml(data)
                    adresses.append(unicode(te.toPlainText()))
                # récup de la liste ages dans la colonne d'indice 2
                ages = []
                j = 2
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    ages.append(unicode(self.model.data(modelindex).toString()))
                # affichage
                QtGui.QMessageBox.information(self,
                    u"Etat des variables",
                    unicode(names) + '\n' + unicode(adresses) + '\n' + unicode(ages))
                event.accept()
            else:
                event.ignore()
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = Window()
        fen.show()
        sys.exit(app.exec_())
    Merci encore!


    [Edit] l'exemple avec le combobox ne marche pas correctement. une modification de la valeur affichée est bien intégrée dans le modèle, mais le réaffichage (après avoir fait "suivant" et "précédent") n'affiche pas la bonne valeur précédemment sélectionnée sur le combobox.

    [Edit2] Ça y est: ça marche avec le combobox! J'ai modifié fortement de Delegate. Voilà le code de test complet:

    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
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    #Python 2.7
     
    # ne marche pas bien
     
    import sys, os
     
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Delegate(QtGui.QItemDelegate):
     
        #========================================================================
        def __init__(self, parent=None):
            QtGui.QItemDelegate.__init__(self, parent=None)
     
        #========================================================================
        def setEditorData(self, editor, index):
     
            if isinstance(editor, QtGui.QComboBox):
                data = index.data().toString()
                i = editor.findText(data)
                i = max(i, 0)
                editor.setCurrentIndex(i)
                return    
            QtGui.QItemDelegate.setEditorData(self, editor, index)
     
        #========================================================================
        def setModelData(self, editor, model, index):
     
            if isinstance(editor, QtGui.QComboBox):
                value = editor.currentText()
                model.setData(index, value)
                return
            QtGui.QItemDelegate.setModelData(self, editor, model, index)
     
    #############################################################################
    class Window(QtGui.QWidget):
        """Classe principale"""
     
        #========================================================================
        def __init__(self, parent=None):
            """Constructeur"""
            super(Window, self).__init__(parent)
            self.setWindowTitle(u"Exemple de QDataWidgetMapper")
     
            self.setupModel()
     
            # Nom
            self.nameLabel = QtGui.QLabel(u"Nom:")
            self.nameEdit = QtGui.QLineEdit()
     
            # Adresse        
            self.addressLabel = QtGui.QLabel(u"Adresse:")
            self.addressEdit = QtGui.QTextEdit()
            self.addressEdit.setAcceptRichText(False)
     
            # Type
            self.typeLabel = QtGui.QLabel(u"Type:")
            self.typeComboBox = QtGui.QComboBox()
            self.typeComboBox.setModel(self.typeModel)
     
            # Navigation
            self.nextButton = QtGui.QPushButton(u"Suivant")
            self.previousButton = QtGui.QPushButton(u"Précédent")
     
            # Widget de correspondance
            self.mapper = QtGui.QDataWidgetMapper(self)
            self.mapper.setModel(self.model)
     
            self.mapper.setItemDelegate(Delegate(self))
     
            self.mapper.addMapping(self.nameEdit, 0)
            self.mapper.addMapping(self.addressEdit, 1)
            self.mapper.addMapping(self.typeComboBox, 2)
     
            #Connexions
            self.connect(self.previousButton, QtCore.SIGNAL("clicked()"), self.mapper, QtCore.SLOT("toPrevious()"))
            self.connect(self.nextButton, QtCore.SIGNAL("clicked()"), self.mapper, QtCore.SLOT("toNext()"))
            self.connect(self.mapper,QtCore.SIGNAL("currentIndexChanged(int)"), self.updateButtons)
     
            self.mapper.toFirst() # Nécessaire au premier lancement 
            self.updateButtons(0) # 
     
            # positionnement des widgets dans la fenêtre
            posit = QtGui.QGridLayout()
            # 1ère ligne
            posit.addWidget(self.nameLabel, 0, 0, 1, 1)
            posit.addWidget(self.nameEdit, 0, 1, 1, 2)
            posit.addWidget(self.nextButton, 0, 3, 1, 1)
            # 2e ligne
            posit.addWidget(self.addressLabel, 1, 0, 1, 1)
            posit.addWidget(self.addressEdit, 1, 1, 2, 2)
            posit.addWidget(self.previousButton, 1, 3, 1, 1)
            # 3e ligne
            posit.addWidget(self.typeLabel, 3, 0, 1, 1)
            posit.addWidget(self.typeComboBox, 3, 1, 1, 2)
            # mise en place
            self.setLayout(posit)
     
        #========================================================================
        def setupModel(self):
                """Crée le modèle"""
                self.model = QtGui.QStandardItemModel(5, 3, self)
     
                names = [u"Alice", u"Bob", u"Carol", u"Donald", u"Emma"]
                adresses = [u"", u"", u"", u"", u""]
                types = [u"Home", u"Home", u"Work",u"Other", u""]
     
                for row in range(0,5):
                    item = QtGui.QStandardItem(names[row])
                    self.model.setItem(row, 0, item)
     
                    item = QtGui.QStandardItem(adresses[row])
                    self.model.setItem(row, 1, item)
     
                    item = QtGui.QStandardItem(types[row])
                    self.model.setItem(row, 2, item)
     
                # liste des item du combobox
                self.typeModel=QtGui.QStringListModel([u"Home", u"Work", u"Other"])
     
        #========================================================================
        def updateButtons(self, index):
                """Met à jour l'état des boutons si nécessaire"""
                self.previousButton.setEnabled(index>0)
                self.nextButton.setEnabled(index<self.model.rowCount()-1)
     
        # =======================================================================
        def keyPressEvent(self, event):
            if event.key() == QtCore.Qt.Key_Q and (event.modifiers() & QtCore.Qt.ControlModifier):
                nbrow = self.model.rowCount()
                nbcol = self.model.columnCount()
                # récup de la liste names dans la colonne d'indice 0
                names = []
                j = 0
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    names.append(unicode(self.model.data(modelindex).toString()))
                # récup de la liste adresses dans la colonne d'indice 1
                adresses = []
                j = 1
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    data = self.model.data(modelindex).toString()
                    te = QtGui.QTextEdit()
                    te.setHtml(data)
                    adresses.append(unicode(te.toPlainText()))
                # récup des données issues du combobox
                types = []
                j = 2
                for i in range(0, nbrow):
                    modelindex = self.model.index(i, j)
                    types.append(unicode(self.model.data(modelindex).toString()))
                # affichage
                QtGui.QMessageBox.information(self,
                    u"Etat des variables",
                    unicode(names) + '\n' + unicode(adresses) + '\n' + unicode(types))
                event.accept()
            else:
                event.ignore()
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = Window()
        fen.show()
        sys.exit(app.exec_())
    S'il y avait plusieurs combobox, il faudrait dans le delegate tester le numéro de colonne dans le modèle.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

Discussions similaires

  1. Widget de correspondance de données
    Par Lquatre dans le forum Qt
    Réponses: 0
    Dernier message: 15/11/2011, 22h46
  2. Non correspondance de données
    Par xehyan dans le forum Langage SQL
    Réponses: 4
    Dernier message: 12/01/2009, 10h13
  3. widget d'affichage des données avec gtk+
    Par sabrinabest dans le forum GTK+ avec C & C++
    Réponses: 3
    Dernier message: 11/09/2007, 17h31

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