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 :

Séparer son IHM en plusieurs fichiers UI [QtGui]


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut Séparer son IHM en plusieurs fichiers UI
    Bonjour,
    je débute en PyQt, et j'ai le problème suivant: comme mon interface graphique est assez complexe, je voudrais la "séparer" en plusieurs fichiers ui.
    Pour cela, dans mon IHM principale, j'inclus des QWidgets, puis je fais "promouvoir en..." et j'ajoute ainsi les autres fichiers *.ui de type QWidget que j'ai créé.
    Cependant je pense que j'ai loupé quelque chose, notamment, lorsque je crée un nouveau widget promu, Qtdesigner me demande un nom de fichier d'entête *.h. A quoi correspond ce fichier?
    Lorsque je lance mon programme j'ai le message d'erreur suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ImportError: no module named MonWidget
    Et cela doit sans doute être lié au fait que je n'ai pas créé ces fichiers d'entête?
    Merci d'avance pour votre aide.

  2. #2
    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,

    Est-ce que tu utilises uic.load() pour tous ces fichiers y compris la main window ou bien tu les convertis en Python d'abord ?

    Dans le premier cas, ça me parait compliqué parce que uic.load() transforme les chargements des widgets promus en import de la forme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    from chemin.dossier.widgets import monWidget.ui
    ce qui échoue inévitablement.

    Dans l'autre cas, tu utilises un simple widget comme emplacement réservé, tu le promeus en lui donnant le nom de la classe du widget en question, le chemin du fichier du widget au lieu du fichier d'entête et après conversion de ta main window en python, tu rectifies la ligne d'import du widget personnalisé. Là tu seras aussi confrontée au fait que la conversion ui --> py ne crée pas de méthode __init__(), donc il faudra aussi modifier cela.

    Une autre solution est d'écrire ta main window seule et d'y intégrer les différents composants avec le module uic.


    Edit: Voir ici aussi: http://www.mail-archive.com/pyqt@riv.../msg17893.html

  3. #3
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut
    Merci pour tes réponses,
    je convertis mes fichiers en python avec pyuic4.

    tu utilises un simple widget comme emplacement réservé, tu le promeus en lui donnant le nom de la classe du widget en question, le chemin du fichier du widget au lieu du fichier d'entête
    C'est ce que j'avais fait, mais je ne sais pas comment remplir le champ "fichier d'entête": tu dis le chemin du fichier, mais ici mon fichier MonWidget.py se trouve dans le même répertoire que mon fichier MaMainWindow.py donc je ne sais pas quoi mettre!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tu rectifies la ligne d'import du widget personnalisé
    Du coup il faudra que je refasse cette manip à chaque fois que je régénère mon fichier MaMainWindow.py, n'y a t-il pas un moyen que la ligne d'import soit directement correcte?

    la conversion ui --> py ne crée pas de méthode __init__(), donc il faudra aussi modifier cela
    Pourquoi créer la méthode __init__ ici? Que faut il mettre dedans?

    Désolée je ne comprends pas encore tout...

  4. #4
    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,

    En ce qui me concerne, j'ai aussi des projets complexes avec de nombreuses fenêtres, mais j'utilise une méthode plus rustique, qui me donne pleinement satisfaction:

    1- chaque fenêtre est composée de 4 fichiers:
    - fenetre.py =>le script principal contenant la classe de la fenêtre héritant de QWidget ou QMainWindows
    - fenetre_ui.ui => le fichier XML produit par Designer
    - fenetre_ui.bat => la ligne d'instruction avec pyuic4 permettant d'automatiser la conversion en .py (un simple double clic dans le navigateur de fichiers)
    - fenetre_ui.py => le résultat de la conversion en Python du fichier issu de Designer.

    2- le script fenetre (fenetre.py) importe fenetre_ui.py en y ajoutant tout ce que Designer n'a pas pu apporter (les méthodes de traitement par exemple).

    3- la (ou les) fenetre principale du programme (celle qui est lancée à partir de l'OS) se trouve à la racine du projet.

    4- toutes les autres fenêtres appelées se trouvent dans des sous-répertoires construits comme des packages (avec les __init__).

    5- en plus, les fonctions utilitaires ayant un caractère général se trouve dans un répertoire "bibliothèque", lui aussi construit comme un package.

    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
    programme
        fenetre.py
        fenetre_ui.ui
        fenetre_ui.bat
        fenetre_ui.py
     
        fenetre2 
            __init__.py
            fenetre2.py
            fenetre2_ui.ui
            fenetre2_ui.bat
            fenetre2_ui.py
     
        bibliotheque
            __init__.py
            biblio.py
    fenetre.py appelle fenetre2.py de la façon suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    from fenetre2.fenetre2 import Fenetre2
    ...
            self.fen2 = Fenetre2(...)
            self.fen2.setAttribute(QtCore.Qt.WA_DeleteOnClose)
            self.fen2.setWindowModality(QtCore.Qt.NonModal)
            #si modale: self.fen2.setWindowModality(QtCore.Qt.ApplicationModal)
            self.fen2.show()
    Dans des cas plus complexes, on peut faire que à sa fermeture, fenetre2 envoie un message de fermeture (emit) à la fenetre appelante, avec si nécessaire la transmission de données. De même, à la fermeture de la fenêtre principale de fenetre.py (closeEvent), on peut vérifier que toutes les fenetres appelées sont bien fermées, et si ce n'est pas le cas de les fermer.. ou de refuser la fermeture.

    A noter que cette méthode est facilement acceptée par cx_freeze pour faire un logiciel "standalone" (.exe sous Windows).

  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
    Personnellement je préfère, comme tyrtamos, modifier moi-même la mainWindow pour y insérer les éléments qui n'y ont pas étés placés lors de la création de celle-ci avec le Designer.

    C'est tout à fait normal de diviser une interface en plusieurs modules, surtout si l'on prévoit que cette interface devra subir des changements.

    Par contre, faire ceci sans modifications des codes produit par pyuic4 je n'étais pas sur que ce soit possible, et pourtant il semble bien que oui. Et sans utiliser les promotions de widgets.

    Exemple:
    Une mainWindow et un widget designés séparément, soit mwin.ui et lst.ui
    On converti:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    vincent@tiemoko:~/Bureau$ pyuic4 -x mwin.ui -o mwin.py
    vincent@tiemoko:~/Bureau$ pyuic4 lst.ui -o lst.py
    On edite mwin.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
     
    # -*- coding: utf-8 -*-
     
    # Form implementation generated from reading ui file 'mwin.ui'
    #
    # Created: Thu Jun  6 14:43:43 2013
    #      by: PyQt4 UI code generator 4.9.1
    #
    # WARNING! All changes made in this file will be lost!
     
    from PyQt4 import QtCore, QtGui
     
    try:
        _fromUtf8 = QtCore.QString.fromUtf8
    except AttributeError:
        _fromUtf8 = lambda s: s
     
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName(_fromUtf8("MainWindow"))
            MainWindow.resize(591, 465)
            self.centralwidget = QtGui.QWidget(MainWindow)
            self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
            self.gridLayout = QtGui.QGridLayout(self.centralwidget)
            self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
            self.verticalLayout = QtGui.QVBoxLayout()
            self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
            self.horizontalLayout = QtGui.QHBoxLayout()
            self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
            self.treeView = QtGui.QTreeView(self.centralwidget)
            self.treeView.setObjectName(_fromUtf8("treeView"))
            self.horizontalLayout.addWidget(self.treeView)
            self.widget = QtGui.QWidget(self.centralwidget)
            self.widget.setObjectName(_fromUtf8("widget"))
            self.horizontalLayout.addWidget(self.widget)
            self.verticalLayout.addLayout(self.horizontalLayout)
            self.horizontalLayout_2 = QtGui.QHBoxLayout()
            self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
            spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
            self.horizontalLayout_2.addItem(spacerItem)
            self.pushButton = QtGui.QPushButton(self.centralwidget)
            self.pushButton.setObjectName(_fromUtf8("pushButton"))
            self.horizontalLayout_2.addWidget(self.pushButton)
            self.verticalLayout.addLayout(self.horizontalLayout_2)
            self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QtGui.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 591, 20))
            self.menubar.setObjectName(_fromUtf8("menubar"))
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QtGui.QStatusBar(MainWindow)
            self.statusbar.setObjectName(_fromUtf8("statusbar"))
            MainWindow.setStatusBar(self.statusbar)
     
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
     
        def retranslateUi(self, MainWindow):
            MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
            self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
     
     
    if __name__ == "__main__":
        import sys
        app = QtGui.QApplication(sys.argv)
        MainWindow = QtGui.QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())
    On remarque, ligne 33, que j'ai placé un widget receveur en attente (placeholder dans les docs en anglais), c'est dans celui-ci que je vais placer mon widget créé séparément et dans lequel j'ai mis un QListWidget et un QPushButton.

    Pour cela je modifie uniquement les dernières lignes du code:
    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
     
    if __name__ == "__main__":
        import sys
        from lst import Ui_Form             # Import du widget depuis lst.py (même dossier)
        app = QtGui.QApplication(sys.argv)
        wdg = QtGui.QWidget()               # Création d'un widget support
        Form = Ui_Form()                    # Instance de la classe Ui_Form
        Form.setupUi(wdg)                   # on initialise son contenu dans le widget support
        MainWindow = QtGui.QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        layout = QtGui.QGridLayout(ui.widget)   # il faut un layout au widget receveur
        layout.addWidget(wdg, 0, 0, 1, 1)       # on y place notre widget support
        MainWindow.show()                   # et le tour est joué.
        sys.exit(app.exec_())
    Le code de lst.py pour pouvoir tester:
    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
     
    # -*- coding: utf-8 -*-
     
    # Form implementation generated from reading ui file 'lst.ui'
    #
    # Created: Thu Jun  6 14:59:12 2013
    #      by: PyQt4 UI code generator 4.9.1
    #
    # WARNING! All changes made in this file will be lost!
     
    from PyQt4 import QtCore, QtGui
     
    try:
        _fromUtf8 = QtCore.QString.fromUtf8
    except AttributeError:
        _fromUtf8 = lambda s: s
     
    class Ui_Form(object):
        def setupUi(self, Form):
            Form.setObjectName(_fromUtf8("Form"))
            Form.resize(305, 332)
            self.gridLayout = QtGui.QGridLayout(Form)
            self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
            self.verticalLayout = QtGui.QVBoxLayout()
            self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
            self.listWidget = QtGui.QListWidget(Form)
            self.listWidget.setObjectName(_fromUtf8("listWidget"))
            self.verticalLayout.addWidget(self.listWidget)
            self.horizontalLayout = QtGui.QHBoxLayout()
            self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
            spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
            self.horizontalLayout.addItem(spacerItem)
            self.pushButton = QtGui.QPushButton(Form)
            self.pushButton.setObjectName(_fromUtf8("pushButton"))
            self.horizontalLayout.addWidget(self.pushButton)
            self.verticalLayout.addLayout(self.horizontalLayout)
            self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
     
            self.retranslateUi(Form)
            QtCore.QMetaObject.connectSlotsByName(Form)
     
        def retranslateUi(self, Form):
            Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
            self.pushButton.setText(QtGui.QApplication.translate("Form", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
    Question personnelle, je sais, mais je préfère hacker les fichiers d'interface que cette méthode.

  6. #6
    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,

    Petit complément à mon message précédent: je ne modifie jamais à la main le code Python issu de Designer + pyuic4, et ceci pour une raison évidente: chaque nouvelle évolution du dessin de la fenêtre par Designer effacerait ces modifications!

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

Discussions similaires

  1. Partager son programme en plusieurs fichiers
    Par akuma8 dans le forum Arduino
    Réponses: 2
    Dernier message: 14/12/2014, 13h30
  2. Diviser son code en plusieurs fichiers ?
    Par tintin72 dans le forum jQuery
    Réponses: 4
    Dernier message: 13/09/2013, 16h02
  3. Réponses: 1
    Dernier message: 08/04/2010, 16h53
  4. Comment répartir son script dans plusieurs fichiers
    Par volkukan dans le forum Général Python
    Réponses: 2
    Dernier message: 25/11/2009, 12h40
  5. répartir son code dans plusieurs fichiers
    Par peuf23 dans le forum Débuter
    Réponses: 5
    Dernier message: 10/09/2008, 12h00

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