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 :

Problème de multi-fenêtre


Sujet :

PyQt Python

  1. #1
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 12
    Par défaut Problème de multi-fenêtre
    Bonjour, je vous explique mon problème :
    Lorsque je tente de créer une fenêtre tout va bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    W = Worksoft()
    loginApp = QtGui.QApplication(sys.argv)
    loginForm = QtGui.QWidget()
    W.loginWindowSetupUi(loginForm)
    loginForm.show()
    sys.exit(loginApp.exec_())
    La fenêtre est définie dans une fonction elle même contenue dans une classe avec toutes les fonctions (dont la prochaine fenêtre).

    Puis lorsque la fenêtre de login est passée avec succès, j'appelle la deuxième fenêtre :
    (A l'intérieur d'une fonction de la classe Worksoft)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    self.mainApp = QtGui.QApplication(sys.argv)
    self.MainWindow = QtGui.QMainWindow()
    self.mainWindowSetupUi(self.MainWindow)
    self.MainWindow.show()
    sys.exit(self.mainApp.exec_())
    L'interpréteur me gratifie d'une magnifique erreur :
    EOFError: [WinError 10054] Une connexion existante a dû être fermée par l'hôte distant

    En entier :

    Traceback (most recent call last):
    File "<string>", line 73, in execInThread
    File "<string>", line 44, in __call__
    File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\netref.py", line 196, in __call__
    File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\netref.py", line 71, in syncreq
    File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 431, in sync_request
    File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 379, in serve
    File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 337, in _recv
    File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\channel.py", line 50, in recv
    File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\stream.py", line 166, in read
    EOFError: [WinError 10054] Une connexion existante a dû être fermée par l'hôte distant
    Comment faire ?
    Merci d'avance

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

    Tu ne peux instancier qu'une QApplication et une seule.

    Instancie là au tout début de ton code, idéalement là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        ...
    et tu effaces la deuxième instance.

  3. #3
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 12
    Par défaut
    Merci Mais comment ça se présente exactement ?
    Je développe mon problème :
    J'ai une fenêtre principale mais avant d'y accéder, je dois lancer une fenêtre de login. Pour lancer la fenêtre de login (qui est un widget [Je ne sais pas si c'est la bonne méthode mais bon]), c'est relativement simple, je fais comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    app = QtGui.QApplication(sys.argv)
    loginForm = QtGui.QWidget()
    W = Worksoft()
    W.loginWindowSetupUi(loginForm)
    loginForm.show()
    sys.exit(app.exec_())
    Ensuite, sur la fenêtre de login, il y a un bouton Connexion qui est relié par un signal à une fonction login. Si le login est bon, il doit exécuter la fenêtre principale.
    En sachant que la classe héberge le constructeur de la fenêtre login (loginWindowSetupUi()) et le constructeur de la fenêtre principale (mainWindowSetupUi()). Quelle est la commande pour exécuter la fenêtre principale à partir de la fonction login ?

  4. #4
    Rédacteur/Modérateur

    Avatar de Jiyuu
    Homme Profil pro
    Développeur amateur
    Inscrit en
    Janvier 2007
    Messages
    2 456
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur amateur
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 456
    Billets dans le blog
    15
    Par défaut


    Pour commencer, merci de penser à l'avenir à la balise [CODE], ça donne plus de visibilité aux codes.

    Ensuite pour revenir à ton problème je t'invite à lire cet article qui peut sûrement t'aider.

    Une autre manière de faire serait d'avoir une seule et unique fenêtre. Au démarrage de l'application tu affiches un conteneur avec les zones à renseigner pour se loguer. Si les tests sont bons alors tu détruits ce conteneur et ensuite tu affiches la vue principale de ton programme.

    Bonne continuation.
    Initiation à Qt Quick et QML : Partie 1 - Partie 2
    En cas de besoin, pensez à la
    Mon site et mes tutoriaux sur Developpez.com
    Pas de question technique par MP... Les forums sont là pour ça

  5. #5
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 12
    Par défaut
    J'avais déjà regardé l'article qui malheureusement ne m'a pas aidé :/
    Et pour l'histoire des conteneurs ça à l'air interessant
    Pas trop dur à gérer ?
    J'ai au total 6 fenêtres déjà faites avec Tkinter à transcrire en PyQt4 :
    - Fenêtre de login
    - Fenêtre principale
    - Fenêtre d'administration
    - Fenêtre transaction
    - Fenêtre d'upload
    - Fenêtre information des prix

  6. #6
    Rédacteur/Modérateur

    Avatar de Jiyuu
    Homme Profil pro
    Développeur amateur
    Inscrit en
    Janvier 2007
    Messages
    2 456
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur amateur
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 456
    Billets dans le blog
    15
    Par défaut
    PyQt est relativement simple d'utilisation, donc je pense que ça ira assez simplement.

    Ton souci sera surtout que tu vas t’apercevoir que tu peux faire des tas de trucs avec et que du coup tu vas vouloir faire plus de choses avec la nouvelle version de ton programme
    Initiation à Qt Quick et QML : Partie 1 - Partie 2
    En cas de besoin, pensez à la
    Mon site et mes tutoriaux sur Developpez.com
    Pas de question technique par MP... Les forums sont là pour ça

  7. #7
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 12
    Par défaut
    Donc je pourrais masquer et refaire apparaitre chacun de mes conteneurs ? Est-ce au moins possible de créer plusieurs fenêtre (simultanément ou non ) à partir d'une SEULE classe ? Si oui, je pourrais avoir un tout petit exemple fonctionnel siouplait ? Merci encore de prendre du temps à régler mon problème !

  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
    Multi fenêtres ne signifie pas grand chose avec Qt.

    Traditionnellement, tu disposes d'une fenêtre principale, et d'autant de boîtes de dialogue que tu veux, réutilisable à merci, bien sur. Bien que recréable soit plus exact que réutilisable.

    Les dialogues ne sont pas dépendant de ta main window, voir exemple ci dessous où un dialogue est lancé avant création de la fenêtre principale, tu peux faire communiquer entre eux le core de l'application, la fenêtre principale, le dialogue, et pourquoi pas, un deuxième dialogue et plus si affinités.

    Un exemple simple qui se rapproche de ce que tu veux faire pour lancer ton appli:
    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
     
    # -*- coding: utf-8 -*-
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    class Main(object):
        def __init__(self):
            self.ui = MainWindow(self)
            self.ui.show()
     
    class MainWindow(QtGui.QMainWindow):
        def __init__(self, main, parent=None):
            super(MainWindow, self).__init__(parent)
            self.main = main
            self.topwidget = QtGui.QWidget()
            self.grid = QtGui.QGridLayout(self.topwidget)
            self.vlayout = QtGui.QVBoxLayout()
            self.label = QtGui.QLabel("The Main Window.", self.topwidget)
            self.vlayout.addWidget(self.label)
            self.quit = QtGui.QPushButton("Close", self.topwidget)
            self.vlayout.addWidget(self.quit)
            self.grid.addLayout(self.vlayout, 0, 0, 1, 1)
            self.setCentralWidget(self.topwidget)
            self.quit.clicked.connect(sys.exit)
     
    class LogginDialog(object):
        def setupUi(self, Dialog):
            self.grid = QtGui.QGridLayout(Dialog)
            self.cancel = QtGui.QPushButton("Cancel", Dialog)
            self.cancel.clicked.connect(Dialog.reject)
            self.log = QtGui.QPushButton("Log me", Dialog)
            self.log.clicked.connect(Dialog.accept)
            self.grid.addWidget(self.cancel, 0, 0, 1, 1)
            self.grid.addWidget(self.log, 0, 1, 1, 1)
            Dialog.show()
     
    def loggin():
        dialog = QtGui.QDialog()
        lg = LogginDialog()
        lg.setupUi(dialog)
        return dialog.exec_()
     
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        if loggin():
            main = Main()
            sys.exit(app.exec_())
        sys.exit()
    Il n'y a aucune finitions, c'est brut de décoffrage, mais c'est fonctionnel.

    Dans cet exemple la fonction loggin() montre une façon d'instancier un dialogue, et donc tu peux placer ce type de fonction dans ton core et la rappeler chaque fois que nécessaire. Mais donc, cela montre bien qu'un dialogue n'est pas réutilisé mais recréé.

  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,

    La solution de VinsS est ok. Il y en a une autre: lancer la fenêtre principale sans l'afficher, et c'est elle qui affiche la petite fenêtre du login. Si la réponse est ok, la fenêtre principale peut s'afficher elle-même (self.show()). Sinon: la fenêtre se détruit (self.close()) après avoir affiché un message d'erreur. Un des avantages est de pouvoir figer la fenêtre au bout d'un certain temps d'inaction ou avant une action à plus haut privilège, pour demander de nouveau le login.

    Bien entendu, les mots de passe ne doivent pas être contenus en clair, mais seulement sous la forme cryptée: voir le module hashlib. Et les comparaisons se font entre valeurs cryptées uniquement.

    Voilà un petit code de test (désolé, c'est en Python 2.7, mais ça doit être assez simple de convertir en 3.3).

    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
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    # python 2.7
     
    import sys
    from PyQt4 import QtCore, QtGui
     
     
    #############################################################################
    class Login(QtGui.QWidget):
     
        finlogin = QtCore.pyqtSignal(list) # création d'un nouveau signal  
     
        #========================================================================
        def __init__(self, parent=None):
            super(Login, self).__init__(parent)
            self.setWindowTitle(u"Login:")
     
            self.nom = QtGui.QLineEdit(self)
            self.nom.setText(u"identifiant?")
            self.nom.returnPressed.connect(self.close)
     
            self.mdp = QtGui.QLineEdit(self)
            self.mdp.setText(u"mot de passe?")
            self.mdp.setEchoMode(QtGui.QLineEdit.Password) # ne pas afficher le mot de passe
            self.mdp.returnPressed.connect(self.close)
     
            self.bouton = QtGui.QPushButton('Login', self)
            self.bouton.clicked.connect(self.close)
     
            posit = QtGui.QGridLayout()
            posit.addWidget(self.nom, 0, 0)
            posit.addWidget(self.mdp, 1, 0)
            posit.addWidget(self.bouton, 2, 0)
            self.setLayout(posit)
     
            self.nom.setFocus()
            self.nom.selectAll()
     
        def closeEvent(self, event):
            """exécuté à chaque fermeture de la fenêtre"""
            # préparation de la réponse rep
            rep = [unicode(self.nom.text()), unicode(self.mdp.text())]
            # envoi du signal "finlogin" avec le couple [nom, motdepasse]
            self.finlogin.emit(rep)
            # acceptation de la fermeture de la fenêtre
            event.accept()
     
    #############################################################################
    class Principal(QtGui.QMainWindow):
     
        #========================================================================
        def __init__(self, parent=None):
            """Initialise la fenêtre"""
            super(Principal, self).__init__(parent)
     
            # mettre un fond (nécessaire avec un QMainWindow)
            self.setCentralWidget(QtGui.QFrame())
     
            # créer un bouton qui ne fait rien ici
            self.bouton = QtGui.QPushButton(u"Bouton bidon", self.centralWidget())
     
            # positionner sur le fond de la fenêtre
            posit = QtGui.QGridLayout()
            posit.addWidget(self.bouton, 0, 0)
            self.centralWidget().setLayout(posit)
     
            # appeler la petite fenêtre de login
            self.login = Login()
            # préparer à recevoir le signal de fin de login, et si oui, 
            #   lancer la méthode veriflogin
            self.login.finlogin.connect(self.veriflogin)
            self.login.show()
     
        #========================================================================
        def veriflogin(self, rep):
     
            # base de données des logins enregistrés 
            self.login = {"toto":"mdptoto", "titi":"mdptiti", "tata":"mdptata"}
     
            if rep[0] in self.login and self.login[rep[0]]==rep[1]:
                self.show() # affichage de la fenêtre principale
            else:
                QtGui.QMessageBox.critical(self, 
                    u"Login",
                    u"Désolé, mauvais identifiant ou mauvais mot de passe")
                self.close()    
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        main = Principal()
        # pas de main.show() ici!
        sys.exit(app.exec_())
    A part ça, construire une application multi-fenêtre en PyQt4 est très facile. N'importe quelle fenêtre construite (héritant de QWidget ou QMainWindow) peut appeler n'importe quelle autre fenêtre, modale ou non, lui passer des paramètres au lancement et en récupérer à la fermeture. Et n'importe quelle fenêtre construite peut, bien sûr, lancer n'importe quelle fenêtre utilitaire type messagebox ou dialog.

    A noter que pour que le code soit compréhensible, il vaut mieux faire en sorte que chaque fenêtre construite fasse l'objet d'une classe héritant de QWidget ou QMainWindow. On peut alors surcharger les méthodes pour en changer le comportement (exemple ici: closeEvent).

  10. #10
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 12
    Par défaut
    Et donc pour tout mettre dans une classe, je dois oublier ?
    Merci pour toute vos réponses ! Je teste ça Mercredi et je vous redis

  11. #11
    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
    Citation Envoyé par Mizugola Voir le message
    Et donc pour tout mettre dans une classe, je dois oublier ?
    Je confirme.

Discussions similaires

  1. [WD17] Problème de focus Appli multi-fenêtre
    Par Jérôme .G dans le forum WinDev
    Réponses: 12
    Dernier message: 11/09/2013, 15h41
  2. Réponses: 0
    Dernier message: 05/09/2011, 15h16
  3. [WindowListener] Problème pour créé fenêtre
    Par dib258 dans le forum Agents de placement/Fenêtres
    Réponses: 4
    Dernier message: 06/08/2005, 13h57
  4. Problème d'affichage: fenêtres (frames) vides!
    Par NdmaX dans le forum Agents de placement/Fenêtres
    Réponses: 6
    Dernier message: 12/07/2005, 21h23
  5. [Javascript] Problème avec une fenêtre popup.
    Par mika0102 dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 18/05/2005, 10h50

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