2017-11-06 3 views
0

Ich führe eine Funktion, in der ich ein PyQt-Popup öffnen möchte, das so etwas wie "Warten ..." sagt, das so lange dauert, bis die Funktion beendet ist. Danach möchte ich den Text auf "Complete" ändern, für ein oder zwei Sekunden schlafen und das Popup schließen. Ich habe mehrere Möglichkeiten ausprobiert, aber bisher war das nicht erfolgreich. Es sieht aus wie jedes Mal, wenn ich app.exec_() rufe die Funktion hält die Funktion, bis ich das Popup schließe. Ich möchte dies außerhalb des Kontexts der Hauptereignisschleife von PyQt tun (Ich habe versucht, diese Ereignisschleife asynchron ohne Erfolg auszuführen). Wenn ich nicht exec_() rufe, sehe ich das Popup überhaupt nicht. Grundsätzlich möchte ich so etwas:Wie erstellt man ein einfaches PyQt-Popup in der Python-Funktion und schließt es am Ende?

# this is the function that is being run 
def run(): 
    create_popup() # show popup 
    wait_for_some_messages() # do some stuff 
    close_popup() # close popup 

def create_popup(): 
    app = QApplication([]) 
    popup = Popup() 
    popup.show() 

class Popup(QDialog): 
    super().__init__() 
    self.label = QLabel(self) 

Jede Hilfe wird sehr geschätzt. Vielen Dank!

Antwort

1

Ich denke, die Aufgabe, die Sie ausführen möchten, ist schwer, so dass Sie die GUI-Schleife blockieren können, so wird empfohlen, eine QRunnable zu implementieren und starten Sie mit QThreadPool, in der Lauf-Methode wird die schwere Funktion am Ende aufgerufen Aufgabe aktualisiert die Daten durch QMetaObject::invokeMethod, dann werden wir eine QEventLoop verwenden, um 2 Sekunden zu warten und die Methode zu schließen.

class Runnable(QRunnable): 
    def __init__(self, popup, func): 
     QRunnable.__init__(self) 
     self.popUp = popup 
     self.func = func 

    def run(self): 
     # execute hard function 
     self.func() 
     # Update the text shown in the popup 
     QMetaObject.invokeMethod(self.popUp, "setText", 
           Qt.QueuedConnection, 
           Q_ARG(str, "Complete")) 
     # wait 2 seconds 
     loop = QEventLoop() 
     QTimer.singleShot(2000, loop.quit) 
     loop.exec_() 
     # call the close method of the popup 
     QMetaObject.invokeMethod(self.popUp, "close", 
           Qt.QueuedConnection) 


class PopUp(QDialog): 
    def __init__(self, *args, **kwargs): 
     QDialog.__init__(self, *args, **kwargs) 
     self.setLayout(QVBoxLayout()) 
     self.label = QLabel(self) 
     self.layout().addWidget(self.label) 

    @pyqtSlot(str) 
    def setText(self, text): 
     self.label.setText(text) 

# emulate the heavy task 
def func(): 
    for i in range(10000): 
     print(i) 
     QThread.msleep(1) 

if __name__ == '__main__': 
    import sys 

    app = QApplication(sys.argv) 
    w = PopUp() 
    w.show() 
    w.setText("Waiting...") 
    runnable = Runnable(w, func) 
    QThreadPool.globalInstance().start(runnable) 
    w.exec_() 

Plus:

Wenn Sie eine andere Funktion aufrufen wollen einfach ändern:

runnable = Runnable(w, func) 

zu:

runnable = Runnable(w, name_of_your_function) 
+0

Gibt es keine Möglichkeit habe ich kann 'Spaß () 'außerhalb des Geltungsbereichs von PyQt genannt? In meiner Anwendung habe ich einen Prozess ausgeführt und ich denke, es ist irgendwie hässlich, all meine Logik in eine PyQt-App zu verschieben, nur damit ich ein Popup bekomme. In Ihrem Beispiel nehmen wir an, dass 'fun()' bereits aufgerufen wird und ich möchte in der ersten Zeile ein Popup erstellen/anzeigen und in der letzten Zeile schließen. Weißt du, ob das möglich ist? – Stefan

+0

@Stefan Überprüfen Sie meine geänderte Antwort, Sie müssen nur den Namen der Funktion übergeben. – eyllanesc

+0

Danke eyllanesc, ich habe endlich mit deiner Lösung gearbeitet. – Stefan

Verwandte Themen