Frage

Kurze Frage zur Verwendung von QThread in PyQt4 und Python 2.7.Ich erstelle einen Prozess, der von geerbt wurde QObject, und dies einem zuweisen Qthread Ich habe in einer separaten Klasse erstellt (auch geerbt von QObject).

Ist es sicher, das zu bestehen QThread objekt zum Prozessobjekt, damit ich es aufrufen kann thread.msleep(mseconds) innerhalb des Prozesses selbst?

Ich möchte den Thread warten oder schlafen lassen können, aber ich habe diese Zeit gelesen.schlaf (Sekunden) ist bei Verwendung mit PyQt-Multithreading zweifelhaft.

Ich habe versucht, ein Signal vom Prozessobjekt an einen Steckplatz im Hauptthread zu senden (angehängt an thread.msleep(mseconds) für dieses Prozessobjekt), aber ich habe festgestellt, dass dies nicht funktioniert hat;das Prozessobjekt wurde bis zum Abschluss weiter ausgeführt, wobei der Slot erst nach dieser Zeit ausgeführt wurde.Auch nach einer Anpassung der Prioritäten geschah dies weiterhin.Dies ist inakzeptabel, da ich möchte, dass die Prozessschleife kontinuierlich ausgeführt wird.

Irgendwelche anderen Empfehlungen?

War es hilfreich?

Lösung

Es gelang mir schließlich, meinen Code zu ändern, um die Funktionalität zu erreichen, die ich in meiner Frage benötigte:nämlich die Fähigkeit, einen Thread für eine bestimmte Zeit warten oder schlafen zu lassen.

Erstens scheint meine Forschung zu zeigen, dass einer der Hauptgründe für die Unterklasse QThread in Qt wurde schlecht beraten, dass ein Thread sich nicht selbst verwalten kann.Obwohl es zu meiner Frage keine offizielle Dokumentation gibt, kann ich nur vermuten, dass die Übergabe des Thread-Objekts an das darauf ausgeführte Prozessobjekt ebenfalls nicht ratsam wäre, da sich der Thread wieder direkt selbst steuern könnte.

Die Lösung, die ich gefunden habe, ist zu verzichten msleep() insgesamt.Die Qt-Dokumentation zu QThread empfiehlt dies sleep() und wait() funktionen werden vermieden, weil sie nicht gut zur ereignisgesteuerten Natur von Qt passen.Sie empfehlen das QTimer() wird verwendet, um eine Funktion über ein Signal aufzurufen, nachdem sie abgelaufen ist, anstelle von msleep().Standardmäßig QTimer() wird verwendet, um jedes Zeitintervall ein sich wiederholendes Signal zu senden, kann aber auch einmal ein Signal senden mit QTimer.singleShot().In der Dokumentation wird auch angegeben, dass es sicher ist, anzurufen QSleep() innerhalb eines Threads.

Ich benutze nur eine Wiederholung QTimer so rufen Sie einen einzelnen Slot auf foo() mehrmals, aber um eine Verzögerung innerhalb hinzuzufügen foo(), QTimer.singleShot() könnte verwendet werden, um eine zweite Funktion aufzurufen moo() nach einer festgelegten Anzahl von Millisekunden.

BEARBEITEN:Ich habe beschlossen, meinen Threading-Code einzuschließen, der QObject und QThread Unterklassen QObject , um in jedem bestimmten Zeitintervall eine Aufgabe für einen Thread in einer kontinuierlichen Schleife auszuführen.Es ist, soweit ich das beurteilen kann, voll funktionsfähig, könnte aber mit ein wenig Arbeit gebrauchen.

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui

# Class to be assigned to a thread.  
# This should be subclassed to provide new functionality.
class GenericLoop(QtCore.QObject):
    def __init__(self):
        super(GenericLoop, self).__init__()

    # We use this signal to tell the main thread 
    # when this thread is finished.
    finished_Sig = QtCore.pyqtSignal()

    # Default timeout is 0, i.e. do work on thread after 
    # other events have been dealt with
    __timeout = 0
    __processTimer = None
    __args = None
    __kwargs = None

    # We use this function to set the arguments used by run(),
    # if we want to change them mid-execution
    @QtCore.pyqtSlot(tuple, dict)
    def changeArgs(self, args, kwargs):
        self.__args = args
        self.__kwargs = kwargs

    # We can change the timeout used to make the thread run 
    # at given intervals.  Note that the timing is not exact, 
    # since this is impossible with a real time operating system
    @QtCore.pyqtSlot(int)
    def setTimeout(self, mseconds): 
        self.__timeout = int(mseconds)

    # Call either a singleShot QTimer (one execution), 
    # or a normal QTimer (repeated), to start the loop
    @QtCore.pyqtSlot(bool, tuple, dict)
    def startTimer(self, singleShot, args, kwargs):
        self.__processTimer = QtCore.QTimer()
        # We can't pass args and kwargs directly because QTimer.timeout 
        # emits a signal with allowing no contained variables
        # so we copy args and kwargs to local variables instead
        self.changeArgs(args, kwargs)
        if singleShot:
            self.__processTimer.singleShot(self.__timeout, self.callRun)
        else:
            self.__processTimer.timeout.connect(self.callRun)
            self.__processTimer.start(self.__timeout)

    # Call finish from within subclass using self.finish(), or 
    # from another thread using signals.  finish() will stop the 
    # QTimer causing execution of the loop.  The loop can be started again
    # by calling startTimer() or stopTimer() from another thread
    @QtCore.pyqtSlot()
    def stopTimer(self):
        if self.__processTimer.isActive():
            self.__processTimer.stop()
        else:
            print "ERROR: stopTimer() has been called but no timer is running!"

    # We call this to delete the thread.
    @QtCore.pyqtSlot()
    def deleteThread(self):
        self.finished_Sig.emit()

    # This calls run(), in order to enable the passing of 
    # command line arguments to the loop
    @QtCore.pyqtSlot()
    def callRun(self):
        self.run(self.__args, self.__kwargs)

    # run() can be called directly from another thread if required
    @QtCore.pyqtSlot(tuple, dict)
    def run(self, args, kwargs):
        print "ERROR: run() has not been defined!  Stopping thread..."
        self.stopTimer()

# Class for creating threads
class GenericThread(QtCore.QObject):

    # Private variables include the thread.  
    __sendArguments_Sig = QtCore.pyqtSignal(tuple, dict)
    __startTimer_Sig = QtCore.pyqtSignal(int, tuple, dict)
    __setTimeout_Sig = QtCore.pyqtSignal(int)
    __obj = None
    __finished_Sig = None
    __thread = QtCore.QThread()

    # Object to be threaded must be specified when 
    # creating a GenericThread object
    def __init__(self, obj): 
        super(GenericThread, self).__init__()
        self.__obj = obj
        self.moreInit()

    # Set up object on thread
    def moreInit(self):
        self.__thread = QtCore.QThread()
        self.__obj.moveToThread(self.__thread)

        # Allows thread to delete itself when done
        self.__obj.finished_Sig.connect(self.__thread.deleteLater)

        self.__sendArguments_Sig.connect(self.__obj.changeArgs)
        self.__startTimer_Sig.connect(self.__obj.startTimer)
        self.__setTimeout_Sig.connect(self.__obj.setTimeout)
        self.__thread.start()

    # Sets the QTimer timeout and does some checking 
    # to make sure that types are as they should be
    def setTimeout(self, mseconds):
        if mseconds >= 0 and type(mseconds) is type(int()):
            self.__setTimeout_Sig.emit(mseconds)
        elif mseconds < 0 and type(mseconds) is type(int()):
            print "Error: timeout of below 0 ms specified."
        else:
            print "Error: timeout period is specified with a type other than int."

    # Starts a function in the thread via signals, and can pass 
    # it arguments if required. Function executes until QTimer is stopped
    def startLoop(self, *args, **kwargs):
        if (self.__thread == None):
            print "ERROR: Thread has been deleted!"
        else:
            self.__startTimer_Sig.emit(False, args, kwargs)

    # Starts a function in the thread via signals, once
    def startOnce(self, *args, **kwargs):
        if (self.__thread == None):
            print "ERROR: Thread has been deleted!"
        else:
            self.__startTimer_Sig.emit(True, args, kwargs)

# Calls a very simple GUI just to show that the program is responsive
class GUIBox(QtGui.QWidget):

    def __init__(self):
        super(GUIBox, self).__init__()

        self.initUI()

    def initUI(self):

        self.resize(250, 150)

        self.setWindowTitle('Threading!')
        self.show()

# Subclass GenericLoop to reimplement run and such.
class SubClassedLoop(GenericLoop):
    def __init__(self):
        super(SubClassedLoop, self).__init__()

    __i = 0

    @QtCore.pyqtSlot(tuple, dict)
    def run(self, args, kwargs):
        if self.__i>=50:
            self.stopTimer()
            return
        print self.__i, args
        self.__i += 1

app = QtGui.QApplication(sys.argv)

ex = GUIBox()

# Create 3 worker objects to do the actual calculation
worker1 = SubClassedLoop()
worker2 = SubClassedLoop()
worker3 = SubClassedLoop()

# Create 3 thread managing objects to do the thread control
thread1 = GenericThread(worker1)
thread2 = GenericThread(worker2)
thread3 = GenericThread(worker3)

# Set the threads to execute as soon as there is no work to do
thread1.setTimeout(125)
thread2.setTimeout(125)
thread3.setTimeout(125)

# Start threads
thread1.startLoop(1)
thread2.startLoop(2)
thread3.startLoop(3)

# Quit the program when the GUI window is closed
sys.exit( app.exec_() )
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top