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 :

Création de widgets "custom" avec QtDesigner et Qt5


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut Création de widgets "custom" avec QtDesigner et Qt5
    Salut,

    je me permets de relancer le sujet, j'ai voulu créer un widget perso en qt5 mais je n'ai pas retrouvé mon widget dans qt designer.

    Fichier customwidgets/widgets/monlineeditwidget.py
    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
    #! /usr/bin/python3
    # -*- coding: utf-8 -*-
    # Python v3
     
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
     
     
    class MonLineEditWidget(QLineEdit):
     
        #========================================================================
        def __init__(self, parent=None):
            super(MonLineEditWidget, self).__init__(parent)
     
            # mettre un fond de couleur jaune à la ligne de saisie
            self.setStyleSheet("background-color: yellow;")

    Fichier customwidgets/plugins/monlineeditplugin.py
    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
    #! /usr/bin/python3
    # -*- coding: utf-8 -*-
    # Python v3
     
    from PyQt5.QtGui import *
    from PyQt5.QtDesigner import *
     
    # ===== à adapter selon le widget! ==========================================
    # nom (str) du fichier du widget sans extension
    FICHIERWIDGET = "monlineeditwidget"
    # nom (str) de la classe du widget importé
    NOMCLASSEWIDGET = "MonLineEditWidget"
    # nom (str) de l'instance crée dans Designer
    NOMWIDGET = "monLineEditWidget"
    # groupe (str) de widgets pour Designer
    GROUPEWIDGET = "Mes widgets perso"
    # texte (str) pour le toolTip dans Designer
    TEXTETOOLTIP = "Un QLineEdit avec un fond jaune"
    # texte (str) pour le whatsThis dans Designer
    TEXTEWHATSTHIS = "Un QLineEdit avec un fond jaune"
    # icone (rien ou QPixmap) pour présenter le widget dans Designer
    ICONEWIDGET = QIcon()  # sans pixmap, l'icone par défaut est celui de Qt
    # ===========================================================================
     
    # importation de la classe du widget
    modulewidget = __import__(FICHIERWIDGET, fromlist=[NOMCLASSEWIDGET])
    CLASSEWIDGET = getattr(modulewidget, NOMCLASSEWIDGET)
     
    #############################################################################
    class GeoLocationPlugin(QPyDesignerCustomWidgetPlugin):
        """classe pour renseigner Designer sur le widget
           nom de classe à renommer selon le widget
        """
      #========================================================================
        def __init__(self, parent=None):
            super(GeoLocationPlugin, self).__init__(parent)
            self.initialized = False
        #========================================================================
        def initialize(self, core):
            if self.initialized:
                return
            self.initialized = True
         #========================================================================
        def isInitialized(self):
            return self.initialized
        #========================================================================
        def createWidget(self, parent):
            """retourne une instance de la classe qui définit le nouveau widget
            """
            return CLASSEWIDGET(parent)
        #========================================================================
        def name(self):
            """définit le nom du widget dans QtDesigner
            """
            return NOMCLASSEWIDGET
         #========================================================================
        def group(self):
            """définit le nom du groupe de widgets dans QtDesigner
            """
            return GROUPEWIDGET
        #========================================================================
        def icon(self):
            """retourne l'icone qui represente le widget dans Designer
               => un QIcon() ou un QIcon(imagepixmap)
            """
            return ICONEWIDGET
        #========================================================================
        def toolTip(self):
            """retourne une courte description du widget comme tooltip
            """
            return TEXTETOOLTIP
         #========================================================================
        def whatsThis(self):
            """retourne une courte description du widget pour le "What's this?"
            """
            return TEXTEWHATSTHIS
         #========================================================================
        def isContainer(self):
            """dit si le nouveau widget est un conteneur ou pas
            """
            return False
         #========================================================================
        def domXml(self):
            """donne des propriétés du widget pour utilisation dans Designer
            """
            return ('<widget class="{}" name="{}">\n' \
                   ' <property name="toolTip" >\n' \
                   '  <string>{}</string>\n' \
                   ' </property>\n' \
                   ' <property name="whatsThis" >\n' \
                   '  <string>{}</string>\n' \
                   ' </property>\n' \
                   '</widget>\n'\
                   ).format(NOMCLASSEWIDGET, NOMWIDGET, TEXTETOOLTIP, TEXTEWHATSTHIS)
         #========================================================================
        def includeFile(self):
            """retourne le nom du fichier (str sans extension) du widget
            """
            return FICHIERWIDGET
    Fichier designer.py
    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
    #! /usr/bin/python3
    # -*- coding: utf-8 -*-
    # Python v3
     
    import sys, os
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
     
    # lance de la bibliothèque Qt4
    app = QCoreApplication(sys.argv)
     
    # trouve le répertoire d'exécution du présent programme
    repbase = os.path.abspath(os.path.dirname(__file__))
     
    # lit les variables d'environnement dans un dictionnaire
    envdico = os.environ.copy()
     
    env = QProcessEnvironment()
     
    # enregistre dans PYTHONPATH le répertoire des fichiers des widgets
    envdico['PYTHONPATH'] = os.path.join(repbase, 'customwidgets', 'widgets')
    # enregistre dans PYQTDESIGNERPATH le répertoire des fichiers des plugins
    envdico['PYQTDESIGNERPATH'] = os.path.join(repbase, 'customwidgets', 'plugins')
     
    # crée la liste "nom=valeur" des variables d'environnement
    for nom, valeur in envdico.items():
        env.insert(nom, valeur)
     
    # trouve l'adresse du Designer à lancer selon l'OS (corriger selon la configuration)
    designer = QLibraryInfo.location(QLibraryInfo.BinariesPath)
    if sys.platform == 'win32':
        designer += r'\designer.exe'  # Windows
    elif sys.platform == 'linux':
        designer += '/designer'  # Linux
    elif sys.platform == 'darwin':
        designern += '/Designer.app/Contents/MacOS/Designer'  # Mac OS X
    else:
        pass  # autre cas à définir si nécessaire
     
    # lance Designer dans un nouveau processus avec les variables d'environnement
     
     
    proc = QProcess()
    proc.setProcessEnvironment(env)
    proc.start(designer)
    proc.waitForFinished(-1)
    sys.exit(proc.exitCode())
    Une idée ? Bon week end à vous !

  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,

    Je ne l'ai pas encore dit, mais j'ai mis à jour ce thème sur mon site: http://python.jpvweb.com/mesrecettes...uveaux_widgets.

    Cependant, ça fonctionne très bien sur Windows, mais pas sur mon Linux (Linux Mint v17.3): je n'ai pas réussi à voir les widgets personnalisés dans le Designer. J'ai exploré un peu le système, et mon hypothèse est qu'il manque des trucs dans l'implémentation de PyQt5 sur ce Linux. Compte tenu de la filiation entre les distributions, si ça manque sur Linux Mint, il est probable que ça manque aussi sur Ubuntu et peut-être même sur Debian.

    Aussi, ce serait bien si d'autres personnes pouvaient essayer sur d'autres Linux récents qui contiennent PyQt5.

    Je n'ai pas encore essayé sur Linux Mint v18 qui vient de sortir mais ça ne devrait pas tarder. Je ne peux pas le faire maintenant, je ne suis pas chez moi mais dans un chalet dans les Vosges (il fait beau ) et je n'ai internet que par mon téléphone.

  3. #3
    Expert confirmé

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

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

    Si je comprend bien tu ne communiques au Designer que le nom du dossier de tes fichiers plugin.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    envdico['PYQTDESIGNERPATH'] = os.path.join(repbase, 'customwidgets', 'plugins')
    Peu importe que tu donnes le nom du dossier des widgets au PYTHONPATH, le designer n'est pas concerné or il a besoin des widgets aussi.

    J'ai ceci chez moi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    .../qt5/plugins/designer/
                            libpyqt5.so  # t'assurer qu'il est bien là
                            python/
                                    vlineeditplugin.py
                                    VWidgets/
                                            vlineedit.py
    Si tu embarques ton widget perso avec ton programme, inutile de l'ajouter au PYTHONPATH.

    @ tyrtamos, je vois que je n'ai accès que au designer qt4. Je ne m'en étais pas encore préoccupé. Les devtools qt5 sont bien installés mais le designer qt5 n'apparaît nulle part, j'enquête sur l'affaire et je vous dirai quoi.

  4. #4
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Réponse rapide à VinsS :
    la version qt5 est rangée là chez moi :
    /usr/lib/x86_64-linux-gnu/qt5/bin/

  5. #5
    Expert confirmé

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Pour l'emplacement de Qt5 c'est pareil.

    J'ai relevé quelques erreurs dans ton code, je te met les codes simplifiés pour être sûr de ce que l'on fait.
    lineedit.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    # -*- coding: utf-8 -*-
    from PyQt5.QtWidgets import QLineEdit
     
    class LineEdit(QLineEdit):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setStyleSheet("background-color: yellow;")
    lineeditplugin.py
    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
     
    # -*- coding: utf-8 -*-
     
    from PyQt5.QtGui import QIcon
    from PyQt5.QtDesigner import QPyDesignerCustomWidgetPlugin
     
    from widgets.lineedit import LineEdit
     
     
    class LineEditPlugin(QPyDesignerCustomWidgetPlugin):
        """classe pour renseigner Designer sur le widget
           nom de classe à renommer selon le widget
        """
     
        def __init__(self, parent=None):
            super(LineEditPlugin, self).__init__(parent)
            self.initialized = False
     
        def initialize(self, core):
            if self.initialized:
                return
            self.initialized = True
     
        def isInitialized(self):
            return self.initialized
     
        def createWidget(self, parent):
            """retourne une instance de la classe qui définit le nouveau widget
            """
            return LineEdit(parent)
     
        def name(self):
            """définit le nom du widget dans QtDesigner
            """
            return 'LineEdit'
     
        def group(self):
            """définit le nom du groupe de widgets dans QtDesigner
            """
            return 'Custom'
     
        def icon(self):
            """retourne l'icone qui represente le widget dans Designer
               => un QIcon() ou un QIcon(imagepixmap)
            """
            return QIcon()
     
        def toolTip(self):
            """retourne une courte description du widget comme tooltip
            """
            return "Un QLineEdit avec un fond jaune"
     
        def whatsThis(self):
            """retourne une courte description du widget pour le "What's this?"
            """
            return "Un QLineEdit avec un fond jaune"
     
        def isContainer(self):
            """dit si le nouveau widget est un conteneur ou pas
            """
            return False
     
        def domXml(self):
            """donne des propriétés du widget pour utilisation dans Designer
            """
            return '<widget class="LineEdit" name="LineEdit">\n'
     
        def includeFile(self):
            """retourne le nom du fichier (str sans extension) du widget
            """
            return 'widgets.lineedit'
    Il faut encore un fichier __init__.py et on installe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    sudo mkdir -p /usr/lib/x86_64-linux-gnu/qt5/plugins/designer/python/widgets
    sudo cp widgets/lineedit.py /usr/lib/x86_64-linux-gnu/qt5/plugins/designer/python/widgets
    sudo cp widgets/__init__.py /usr/lib/x86_64-linux-gnu/qt5/plugins/designer/python/widgets
    sudo cp lineeditplugin.py /usr/lib/x86_64-linux-gnu/qt5/plugins/designer/python
    Ça, ça doit fonctionner, sauf que ... le designer crash au démarrage
    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
     
    $ designer-qt5
    ImportError: /usr/lib/python3/dist-packages/sip.cpython-34m-x86_64-linux-gnu.so: undefined symbol: PyExc_SystemError
    Error in sys.excepthook:
    Traceback (most recent call last):
      File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook
        from apport.fileutils import likely_packaged, get_recent_crashes
      File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module>
        from apport.report import Report
      File "/usr/lib/python3/dist-packages/apport/report.py", line 30, in <module>
        import apport.fileutils
      File "/usr/lib/python3/dist-packages/apport/fileutils.py", line 23, in <module>
        from apport.packaging_impl import impl as packaging
      File "/usr/lib/python3/dist-packages/apport/packaging_impl.py", line 20, in <module>
        import apt
      File "/usr/lib/python3/dist-packages/apt/__init__.py", line 23, in <module>
        import apt_pkg
    ImportError: /usr/lib/python3/dist-packages/apt_pkg.cpython-34m-x86_64-linux-gnu.so: undefined symbol: PyExc_OSError
     
    Original exception was:
    ImportError: /usr/lib/python3/dist-packages/sip.cpython-34m-x86_64-linux-gnu.so: undefined symbol: PyExc_SystemError
    libGL error: Couldn't dlopen libudev.so.1 or libudev.so.0, driver detection may be broken.
    designer-qt5: ../../../../src/loader/loader.c*:129*:*asserted_dlsym:  l'assertion «*result*» a échoué.
    Abandon (core dumped)
    ... avec, en plus, une erreur dans Apport.

    C'est peut-être ce dont parle Tyrtamos.

    Évidemment, il faut le lancer en ligne de commande pour le voir et ne pas utiliser le script designer.py.

    Ça je l'ai fait sur Trusty 14.04, tu as une version plus récente ?

  6. #6
    Expert confirmé

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Sous Xenial 16.04 pas de crash mais le widget n'apparaît pas.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 18
    Dernier message: 05/06/2013, 12h12
  2. [NetBeans] Création de l'éxé avec Netbeans 3.6
    Par daweed dans le forum NetBeans
    Réponses: 4
    Dernier message: 13/04/2010, 12h37
  3. Creation d'une table avec plusieurs clés
    Par mic79 dans le forum Langage SQL
    Réponses: 6
    Dernier message: 21/06/2005, 11h17
  4. Empecher la création de fichier backup avec vi
    Par Noki dans le forum Applications et environnements graphiques
    Réponses: 4
    Dernier message: 12/11/2004, 14h44
  5. [Creation composant visuel] Problème avec le focus
    Par Ingham dans le forum Composants VCL
    Réponses: 9
    Dernier message: 23/09/2004, 16h59

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