Warning: Undefined array key "DOKU_PREFS" in /home/clients/a4e6fc1ce1761b72982b805de0f418c4/web/python/mesrecettespython/inc/common.php on line 2082
nouveaux_widgets [Les recettes Python de Tyrtamos]

Outils pour utilisateurs

Outils du site


nouveaux_widgets

Warning: Undefined array key -1 in /home/clients/a4e6fc1ce1761b72982b805de0f418c4/web/python/mesrecettespython/inc/html.php on line 1458

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
nouveaux_widgets [2016/06/02 16:51]
tyrtamos
nouveaux_widgets [2016/06/04 08:49]
tyrtamos
Ligne 54: Ligne 54:
 ==== Création du fichier "plugin" ==== ==== Création du fichier "plugin" ====
  
-On va maintenant créer le fichier "plugin" pour renseigner Designer, qu'on appellera "**monlineeditplugin.py**". On le présente ici dans une version standard qui sera facile à adapter pour d'autres widgets (ce n'est pas utile de repartir d'une page blanche à chaque fois!):+On va maintenant créer le fichier "plugin" pour renseigner Designer, qu'on appellera "**monlineeditplugin.py**" (ce nom de fichier doit se terminer par "plugin" en minuscules). On le présente ici dans une version standard qui sera facile à adapter pour d'autres widgetsce n'est pas utile de repartir d'une page blanche à chaque fois!.  
 + 
 +Ainsi, seule la 1ère partie mentionnée "adapter selon le widget" est à adapter, ainsi que le nom de la classe. Pour des cas plus complexes, il faut voir les exemples de PyQt5, et la doc (bon courage!):
  
 <code python>#! /usr/bin/python3 <code python>#! /usr/bin/python3
Ligne 62: Ligne 64:
 from PyQt5 import QtGui, QtDesigner from PyQt5 import QtGui, QtDesigner
    
-# ===== adapter selon le widget! ==========================================+# ===== adapter selon le widget! ==========================================
 # nom (str) du fichier du widget sans extension # nom (str) du fichier du widget sans extension
 FICHIERWIDGET = "monlineeditwidget" FICHIERWIDGET = "monlineeditwidget"
-# nom (str) de la classe du widget importe+# nom (str) de la classe du widget pour importer
 NOMCLASSEWIDGET = "MonLineEditWidget" NOMCLASSEWIDGET = "MonLineEditWidget"
-# nom (str) de l'instance cree dans Designer+# nom (str) de l'instance dans Designer
 NOMWIDGET = "monLineEditWidget" NOMWIDGET = "monLineEditWidget"
-# groupe (str) de widgets pour Designer+# groupe (str) de widgets pour affichage dans Designer
 GROUPEWIDGET = "Mes widgets perso" GROUPEWIDGET = "Mes widgets perso"
 # texte (str) pour le toolTip dans Designer # texte (str) pour le toolTip dans Designer
Ligne 75: Ligne 77:
 # texte (str) pour le whatsThis dans Designer # texte (str) pour le whatsThis dans Designer
 TEXTEWHATSTHIS = "Un QLineEdit avec un fond jaune" TEXTEWHATSTHIS = "Un QLineEdit avec un fond jaune"
-# icone (rien ou QPixmap) pour presenter le widget dans Designer +# icone (rien ou un fichier image ou un QPixmap) pour afficher dans Designer 
-ICONEWIDGET = QtGui.QIcon()  # sans pixmap, l'icone par defaut est celui de Qt+ICONEWIDGET = QtGui.QIcon()  # sans image, l'icone est celui de Qt
 # =========================================================================== # ===========================================================================
    
Ligne 167: Ligne 169:
         return FICHIERWIDGET         return FICHIERWIDGET
 </code> </code>
- 
-Ça parait compliqué comme ça, mais en fait, il n'y a qu'à adapter selon le widget: 
-  * les valeurs des variables en majuscules (utilisez les commentaires dans le code),  
-  * le nom de la classe,  
-  * et, bien sûr, le nom du fichier du widget qui devra se terminer par "plugin". 
  
 ==== Lancement du Designer ==== ==== Lancement du Designer ====
Ligne 178: Ligne 175:
  
 Dans les variables d'environnement de l'OS, on va passer: Dans les variables d'environnement de l'OS, on va passer:
- 
   * le chemin du répertoire "plugins" dans la variable "PYQTDESIGNERPATH"   * le chemin du répertoire "plugins" dans la variable "PYQTDESIGNERPATH"
   * le chemin du répertoire "widget" dans la variable "PYTHONPATH"   * le chemin du répertoire "widget" dans la variable "PYTHONPATH"
 +
 En conséquence, on peut placer ces deux répertoires n'importe où, et "coder en dur" ces 2 chemins dans le code de lancement du Designer, mais c'est un peu dommage. On va donc simplifier ici sur ce point: fixer l'emplacement relatif entre programme et données pour permettre au code de lancement du Designer de trouver automatiquement par calcul les répertoires des widgets. Voilà la structure choisie ici sur le disque: En conséquence, on peut placer ces deux répertoires n'importe où, et "coder en dur" ces 2 chemins dans le code de lancement du Designer, mais c'est un peu dommage. On va donc simplifier ici sur ce point: fixer l'emplacement relatif entre programme et données pour permettre au code de lancement du Designer de trouver automatiquement par calcul les répertoires des widgets. Voilà la structure choisie ici sur le disque:
  
Ligne 239: Ligne 236:
 </code> </code>
  
-Quand vous lancez ce code Python, le Designer vient à l'écran, et vous trouvez dans la colonne de gauche le widget personnalisé "MonLineEditWidget" dans la liste des widgets disponibles, et dans la catégorie définie ("Mes widgets perso"). Et vous pouvez alors l'utiliser comme n'importe quel autre widget. Dans cet exemple, vous voyez dans les propriétés de la colonne de droite que Designer a reconnu le type QLineEdit, et a initialisé les propriétés définies dans le fichier "plugin" (toolTip, whatsThis, styleSheet). +Quand vous lancez ce code Python, le Designer vient à l'écran, et vous trouvez dans la colonne de gauche le widget personnalisé "MonLineEditWidget" dans la liste des widgets disponibles, et dans la catégorie définie ("Mes widgets perso"). Vous pouvez alors l'utiliser comme n'importe quel autre widget. Dans cet exemple, vous voyez dans les propriétés de la colonne de droite que Designer a reconnu le type QLineEdit, et a initialisé les propriétés définies dans le fichier "plugin" (toolTip, whatsThis, styleSheet). 
  
-A noter que ce script qui appelle le Designer nécessite de pouvoir retrouver automatiquement les adresses à l'intérieur de PyQt5. Or, sous Windows, ces adresses sont données par un fichier qt.conf à l'installation dont les données sont fausses!+A noter que ce script qui appelle le Designer nécessite de pouvoir retrouver automatiquement les adresses à l'intérieur de PyQt5. Or, sous Windows, ces adresses sont données par un fichier **qt.conf**, situé à l'installation dans le répertoire de python.exe, et dont **//les données sont fausses!//** Il faut donc le corriger comme suit:
  
 +<code python>[Paths]
 +Prefix = Lib/site-packages/PyQt5
 +Binaries = . 
 +Libraries = .
 +Plugins = plugins
 +Translations = translations
 +</code>
  
 ===== Un autre exemple plus complet ===== ===== Un autre exemple plus complet =====
Ligne 259: Ligne 263:
   * 2ème ligne: un QLabel affichant "Longitude", suivi d'un QDoubleSpinBox permettant l'introduction d'une longitude en nombre décimal (type float).   * 2ème ligne: un QLabel affichant "Longitude", suivi d'un QDoubleSpinBox permettant l'introduction d'une longitude en nombre décimal (type float).
  
-Pour cet exemple, je me suis inspiré du tutoriel du site de nokia: [[http://doc.qt.nokia.com/qq/qq26-pyqtdesigner.html]], traduit en français ici: [[http://qt-quarterly.developpez.com/qq-26/composants-personnalises-pyqt/]].  +Pour cet exemple, je me suis inspiré du tutoriel traduit en français ici: [[http://qt-quarterly.developpez.com/qq-26/composants-personnalises-pyqt/]].  
  
 Voilà le code définissant ce nouveau widget, qui sera contenu dans le fichier "**geolocationwidget.py**" du sous-répertoire "widgets": Voilà le code définissant ce nouveau widget, qui sera contenu dans le fichier "**geolocationwidget.py**" du sous-répertoire "widgets":
Ligne 265: Ligne 269:
 <code python>#! /usr/bin/python3 <code python>#! /usr/bin/python3
 # -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
-# Python v3 +# Python v3 PyQt5 
- +  
-from PyQt4 import QtCore, QtGui +from PyQt5 import QtCore, QtWidgets 
 + 
 ############################################################################# #############################################################################
-class GeoLocationWidget(QtGui.QWidget):+class GeoLocationWidget(QtWidgets.QWidget):
     """widget personnalisé: deux QDoubleSpinBox pour latitude et longitude     """widget personnalisé: deux QDoubleSpinBox pour latitude et longitude
     """     """
 +    
     # crée 2 nouveaux signaux du widget, émis à chaque changement des valeurs     # crée 2 nouveaux signaux du widget, émis à chaque changement des valeurs
     latitudeChanged = QtCore.pyqtSignal(float)     latitudeChanged = QtCore.pyqtSignal(float)
     longitudeChanged = QtCore.pyqtSignal(float)     longitudeChanged = QtCore.pyqtSignal(float)
- +     
-    #========================================================================+   #=========================================================================
     def __init__(self, parent=None):     def __init__(self, parent=None):
-        super(GeoLocationWidget, self).__init__(parent)+        super().__init__(parent)
  
         # crée le 1er spinbox: pour la latitude         # crée le 1er spinbox: pour la latitude
-        latitudeLabel = QtGui.QLabel("Latitude:"+        latitudeLabel = QtWidgets.QLabel("Latitude:"
-        self.latitudeSpinBox = QtGui.QDoubleSpinBox()+        self.latitudeSpinBox = QtWidgets.QDoubleSpinBox()
         self.latitudeSpinBox.setRange(-90.0, 90.0)         self.latitudeSpinBox.setRange(-90.0, 90.0)
         self.latitudeSpinBox.setDecimals(12)         self.latitudeSpinBox.setDecimals(12)
-        # le signal valuechanged est redirigée sur le signal global latitudeChanged +        # le signal valuechanged du spinbox est redirigée sur le signal global latitudeChanged 
-        self.latitudeSpinBox.valueChanged.connect(GeoLocationWidget.latitudeChanged)+        self.latitudeSpinBox.valueChanged.connect(self.latitudeChanged)
  
         # crée le 2e spinbox: pour la longitude         # crée le 2e spinbox: pour la longitude
-        longitudeLabel = QtGui.QLabel("Longitude:"+        longitudeLabel = QtWidgets.QLabel("Longitude:"
-        self.longitudeSpinBox = QtGui.QDoubleSpinBox()+        self.longitudeSpinBox = QtWidgets.QDoubleSpinBox()
         self.longitudeSpinBox.setRange(-180.0, 180.0)         self.longitudeSpinBox.setRange(-180.0, 180.0)
         self.longitudeSpinBox.setDecimals(12)         self.longitudeSpinBox.setDecimals(12)
-        # le signal valuechanged est redirigée sur le signal global longitudeChanged +        # le signal valuechanged du spinbox est redirigée sur le signal global longitudeChanged 
-        self.longitudeSpinBox.valueChanged.connect(GeoLocationWidget.longitudeChanged) +        self.longitudeSpinBox.valueChanged.connect(self.longitudeChanged) 
 + 
         # positionne les 4 objets graphiques en deux lignes dans le QWidget         # positionne les 4 objets graphiques en deux lignes dans le QWidget
-        layout = QtGui.QGridLayout(self)+        layout = QtWidgets.QGridLayout(self)
         layout.addWidget(latitudeLabel, 0, 0)         layout.addWidget(latitudeLabel, 0, 0)
         layout.addWidget(self.latitudeSpinBox, 0, 1)         layout.addWidget(self.latitudeSpinBox, 0, 1)
Ligne 305: Ligne 309:
         layout.addWidget(self.longitudeSpinBox, 1, 1)         layout.addWidget(self.longitudeSpinBox, 1, 1)
         self.setLayout(layout)         self.setLayout(layout)
 +    
     #========================================================================     #========================================================================
-    # permet au Designer de lire/écrire/réinitialiser la latitude +    # permet au Designer de lire/écrire la latitude 
 + 
     @QtCore.pyqtSlot()     @QtCore.pyqtSlot()
     def getLatitude(self):     def getLatitude(self):
-        """retourne la valeur du widget latitudeSpinBox"""+        """retourne la valeur du widget latitudeSpinBox 
 +        """
         return self.latitudeSpinBox.value()         return self.latitudeSpinBox.value()
  
     @QtCore.pyqtSlot(float)     @QtCore.pyqtSlot(float)
     def setLatitude(self, latitude):     def setLatitude(self, latitude):
-        """affecte une nouvelle valeur au widget latitudeSpinBox"""+        """affecte une nouvelle valeur au widget latitudeSpinBox 
 +        """
         if latitude != self.latitudeSpinBox.value():         if latitude != self.latitudeSpinBox.value():
             self.latitudeSpinBox.setValue(latitude)             self.latitudeSpinBox.setValue(latitude)
- 
-    @QtCore.pyqtSlot() 
-    def razLatitude(self): 
-        """ remet à zéro le widget latitudeSpinBox""" 
-        self.latitudeSpinBox.setValue(0.0) 
  
     # définit la propriété pour permettre la configuration par Designer     # définit la propriété pour permettre la configuration par Designer
-    latitude = QtCore.pyqtProperty(float, getLatitude, setLatitude, razLatitude+    latitude = QtCore.pyqtProperty(float, fget=getLatitude, fset=setLatitude) 
 +   
     #========================================================================     #========================================================================
-    # permet au Designer de lire/écrire/réinitialiser la longitude +    # permet au Designer de lire/écrire la longitude 
 + 
     @QtCore.pyqtSlot()     @QtCore.pyqtSlot()
     def getLongitude(self):     def getLongitude(self):
-        """retourne la valeur du widget longitudeSpinBox"""+        """retourne la valeur du widget longitudeSpinBox 
 +        """
         return self.longitudeSpinBox.value()         return self.longitudeSpinBox.value()
 + 
     @QtCore.pyqtSlot(float)     @QtCore.pyqtSlot(float)
     def setLongitude(self, longitude):     def setLongitude(self, longitude):
-        """affecte une nouvelle valeur au widget longitudeSpinBox"""+        """affecte une nouvelle valeur au widget longitudeSpinBox 
 +        """
         if longitude != self.longitudeSpinBox.value():         if longitude != self.longitudeSpinBox.value():
             self.longitudeSpinBox.setValue(longitude)             self.longitudeSpinBox.setValue(longitude)
- + 
-    @QtCore.pyqtSlot() +
-    def razLongitude(self): +
-        """ remet à zéro le widget longitudeSpinBox""" +
-        self.longitudeSpinBox.setValue(0.0) +
     # définit la propriété pour permettre la configuration par Designer     # définit la propriété pour permettre la configuration par Designer
-    longitude = QtCore.pyqtProperty(float, getLongitude, setLongitude, razLongitude)+    longitude = QtCore.pyqtProperty(float, fget=getLongitude, fset=setLongitude)
 </code> </code>
  
Ligne 371: Ligne 369:
 # nom (str) du fichier du widget sans extension # nom (str) du fichier du widget sans extension
 FICHIERWIDGET = "geolocationwidget" FICHIERWIDGET = "geolocationwidget"
-# nom (str) de la classe du widget importé+# nom (str) de la classe du widget pour importer
 NOMCLASSEWIDGET = "GeoLocationWidget" NOMCLASSEWIDGET = "GeoLocationWidget"
-# nom (str) de l'instance crée dans Designer+# nom (str) de l'instance dans Designer
 NOMWIDGET = "geoLocationWidget" NOMWIDGET = "geoLocationWidget"
-# groupe (str) de widgets pour Designer+# groupe (str) de widgets pour affichage dans Designer
 GROUPEWIDGET = "Mes widgets perso" GROUPEWIDGET = "Mes widgets perso"
 # texte (str) pour le toolTip dans Designer # texte (str) pour le toolTip dans Designer
Ligne 381: Ligne 379:
 # texte (str) pour le whatsThis dans Designer # texte (str) pour le whatsThis dans Designer
 TEXTEWHATSTHIS = "Coordonnées GPS" TEXTEWHATSTHIS = "Coordonnées GPS"
-# icone (rien ou un QPixmap) pour présenter le widget dans Designer +# icone (rien ou un fichier image ou un QPixmap) pour afficher dans Designer 
-ICONEWIDGET = QtGui.QIcon()+ICONEWIDGET = QtGui.QIcon()  # sans image, l'icone est celui de Qt
 ... ...
 ... ...
 ############################################################################# #############################################################################
 class GeoLocationPlugin(QtDesigner.QPyDesignerCustomWidgetPlugin): class GeoLocationPlugin(QtDesigner.QPyDesignerCustomWidgetPlugin):
-    """classe pour renseigner Designer sur le widget 
-       à renommer selon le widget 
-    """ 
- 
-    #======================================================================== 
-    def __init__(self, parent=None): 
-        super(GeoLocationPlugin, self).__init__(parent) 
-        self.initialized = False 
 ... ...
 ... ...
nouveaux_widgets.txt · Dernière modification: 2016/06/04 08:49 de tyrtamos