2016-08-09 78 views
1

Ich arbeite an einer komplexen und schlecht kommentierte Qt-basierte Python-Anwendung. Es verwendet einen PySide.QtCore.QTimer.singleShot (int, slot) -Timer, um die Ausführung eines Slots innerhalb eines Threads zu verzögern, und ich bin verwirrt, wie dieser Timer funktioniert.Wie man eine PySide.QtCore.QTimer.singleShot ruft seine Timeout-Methode

Hier ist ein MWE. Dieses Beispiel verwendet den Ansatz, QThread abzuleiten und run() neu zu implementieren. Ich habe folgendes in einer Datei namens timertester.py:

import PySide 
import time 

class SubClassThread(PySide.QtCore.QThread): 

     def run(self): 
       print('called SubClassThread.run()') 
       self.delayed_print() 

     def delayed_print(self): 
       print('called SubClassThread.delayed_print()') 
       PySide.QtCore.QTimer.singleShot(1000, self.print_things) 
       time.sleep(2) 
       print('end of delayed_print()') 

     def print_things(self): 
       print('called print_things') 

Der Code Ich verwende diese (es nennen test.py) zu testen:

import sys 
import time 

import PySide 

from timertester import SubClassThread 

print('Test: QThread subclassing') 
app = PySide.QtCore.QCoreApplication([]) 
sct = SubClassThread() 
sct.finished.connect(app.exit) 
sct.start() 
sys.exit(app.exec_()) 

Der Ausgang des python test.py:

Test: QThread subclassing 
called SubClassThread.run() 
called SubClassThread.delayed_print() 
end of delayed_print() 

Der kuriose Teil ist, dass die an QTimer.singleShot übergebene nie aufgerufen wird (es gibt keine called print_things() in der Ausgabe!) Ich würde jede Klarheit sehr schätzen das kannst du dir verraten. Ich habe das Gefühl, dass mir eine einfache Zutat des Qt-Rahmens fehlt. Bitte ertragen Sie mich - ich habe einige Stunden damit verbracht, nach Antworten zu suchen.

Antwort

1

Die Standardimplementierung von QThread.run() ruft QThread.exec() auf, wodurch die eigene Ereignisschleife des Threads gestartet wird. A QTimer erfordert eine laufende Ereignisschleife, und sein timeout() Signal wird in dem Thread, in dem es gestartet wird, ausgegeben. Ihre Implementierung von run() startet keine Ereignisschleife, so dass der Timer nichts tut.

+0

Diese Antwort brachte mich auf den richtigen Weg, also gebe ich den Scheck. Ich werde dann meine eigene Antwort hinzufügen, damit die Leute den Code sehen können, der letztendlich den Trick gemacht hat. – lensonp

1

Wie @ekhumoro darauf hinwies, konnte meine Reimplementierung von run() exec_() nicht aufrufen. Das war das Hauptproblem. Ich brauchte eine Minute, um herauszufinden, wo ich den Aufruf exec_() ablegen und den Thread beenden konnte, wenn seine Arbeit beendet war. Hier ist der Code, der funktioniert.

Klassendefinition, timertester.py:

import PySide 

class SubClassThread(PySide.QtCore.QThread): 

     def __init__(self,parent=None): 
       print('called SubClassThread.__init__()') 
       super(SubClassThread,self).__init__(parent) 

     def run(self): 
       print('called SubClassThread.run()') 
       self.delayed_print() 
       self.exec_() 

     def delayed_print(self): 
       print('called SubClassThread.delayed_print()') 
       PySide.QtCore.QTimer.singleShot(1000, self.print_things) 
       print('end of delayed_print()') 

     def print_things(self): 
       print('called print_things') 
       self.quit() 

Anwendung, test.py:

import sys 

import PySide 

from timertester import SubClassThread 

print('Test: QThread subclassing') 

# instantiate a QApplication 
app = PySide.QtCore.QCoreApplication([]) 

# instantiate a thread 
sct = SubClassThread() 

# when the thread finishes, make sure the app quits too 
sct.finished.connect(app.quit) 

# start the thread 
# it will do nothing until the app's event loop starts 
sct.start() 

# app.exec_() starts the app's event loop. 
# app will then wait for signals from QObjects. 
status=app.exec_() 

# print status code and exit gracefully 
print('app finished with exit code {}'.format(status)) 
sys.exit(status) 

Und schließlich die Ausgabe von python test.py:

Test: QThread subclassing 
called SubClassThread.__init__() 
called SubClassThread.run() 
called SubClassThread.delayed_print() 
end of delayed_print() 
called print_things 
app finished with exit code 0 

Was ich gelernt habe über QTimers: die Der Aufruf von delayed_print() endet, während der Timer noch r ist Durch das Aufrufen von quit() in der vom Timer aufgerufenen Methode wird die App erst beendet, nachdem diese Methode aufgerufen wurde.

Wenn es weitere Kommentare zu diesem Code oder zu den Aspekten von Qt gibt, die sich auf diese einfache App beziehen, poste bitte! Ich habe einige Schwierigkeiten gehabt, für Anfänger Informationen über PyQt/PySide zu finden.