Hallo zusammen,
ich bin ein Kollege von FloKnoe.
Leider sind die bisherigen Antworten noch nicht wirklich zielführend gewesen, da sie nicht das vorhandene Problem behandeln.
Da wir beide SPS-programmierer sind, kann es natürlich schon sein, dass nicht alles perfekt strukturiert ist. Hier sind wir noch am lernen. Wir sind natürlich für Verbesserungsvorschläge dankbar und werden die uns zu Herzen nehmen. Allerdings wäre es schön erstmal das akute Problem zu verstehen, bevor man das nächste angeht.
Ich habe jetzt den Code nochmal auf ein minimales Beispiel zusammengestrichen um unser Problem richtig darzustellen. (Der Code ist jetzt ein lauffähgies Programm)
Die Klassen "WorkerSignals" und "Worker" haben wir nach langer suche aus entsprechenden Foren gefunden. Welche bei den ersten Versuchen auch funktioniert haben. Nur in Verbindung mit den Klassen/Objekten haben wir jetzt unerklärliche Probleme.
Zum Gesamtverständniss:
Das originale Programm beinhaltet im "__init__.py" den Aufruf der GUI und instanziert andere Objekte, welche für das Programm entscheidend sind.
Die KM(Kopplungsmaschine) erstellt einen TCP-Socket und soll im eigenen Thread per RECV auf Daten warten und bei Erhalt entsprechende Events im HauptThread ausführen. Dafür die SIGNALS.
__init__.py :
Code: Alles auswählen
# IMPORT System
import sys
import os
import logging
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import QtCore
from PyQt5.uic import loadUi
import KM
class WorkerSignals(QObject):
'''
Defines the signals available from a running worker thread.
Supported signals are:
finished
No data
error
tuple (exctype, value, traceback.format_exc() )
result
object data returned from processing, anything
progress
int indicating % progress
'''
finished = pyqtSignal()
error = pyqtSignal(tuple)
result = pyqtSignal(object)
progress = pyqtSignal(int)
class Worker(QRunnable):
'''
Worker thread
Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
:param callback: The function callback to run on this worker thread. Supplied args and
kwargs will be passed through to the runner.
:type callback: function
:param args: Arguments to pass to the callback function
:param kwargs: Keywords to pass to the callback function
'''
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
# Store constructor arguments (re-used for processing)
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
# Add the callback to our kwargs
self.kwargs['progress_callback'] = self.signals.progress
@pyqtSlot()
def run(self):
'''
Initialise the runner function with passed args, kwargs.
'''
# Retrieve args/kwargs here; and fire processing using them
try:
print("DEBUG: try")
result = self.fn(*self.args, **self.kwargs)
except:
print("DEBUG: except")
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else:
print("DEBUG: else")
self.signals.result.emit(result) # Return the result of the processing
finally:
print("DEBUG: finally")
self.signals.finished.emit() # Done
def ausserhalb_func():
print("DEBUG: ausserhalb_func")
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
# Objekt Kopplungsmaschine instanzieren
self.KM = KM.KM()
# Threadpool erstellen
self.threadpool = QThreadPool()
# init Worker
wInit = Worker(self.KM.InitConnection)
wInit.signals.progress.connect(self.innerhalb_func)
self.threadpool.start(wInit)
def innerhalb_func(self):
print("DEBUG: innerhalb_func")
def innerhalb_func_2(self, s):
print ("DEBUG: innerhalb_func_2")
print(s)
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
app.exec_()
KM.py :
Code: Alles auswählen
class KM():
# -------------------- Main --------------------
def InitConnection(self, progress_callback):
print ("DEBUG: InitConnection")
progress_callback.emit(1)
Das Programm macht natürlich jetzt keinen wirklichen Sinn, da sämtliche Inhalte entfernt wurden.
Rein Ablauftechnisch ist es aber genau das Selbe.
Problem ist, dass die Zeile:
wInit.signals.progress.connect(self.innerhalb_func)
Die Funktion nicht ausführt, wenn die Zielfunktion in der "MainWindow" Klasse liegt und wie dargestellt aufgerufen wird.
Welches der Signale man verwendet (progress, Result, finished) ändert auch nichts an dem Problem.
Die Console zeigt beim Ausführen folgendes:
CONSOLE:
DEBUG: try
DEBUG: InitConnection
DEBUG: else
DEBUG: finally
Ändert man die Funktion, welche beim dem Signal aus dem Thread aufgerufen wird auf eine Funktion, welche außerhalb aller Klassen liegt, funktioniert der Aufruf:
wInit.signals.progress.connect(ausserhalb_func)
Die Console zeigt beim Ausführen folgendes:
CONSOLE:
DEBUG: try
DEBUG: InitConnection
DEBUG: else
DEBUG: finally
DEBUG: ausserhalb_func
Allerdings wollen wir natürlich in der Klasse "MainWindow" weiter arbeiten, da dort die entsprechenden Events ausgeführt werden sollen.
Es gibt bestimmt noch zich andere Möglichkeiten um das Thread-Handling in den Griff zu bekommen. Allerdings suchen wir hier schon seit einer Woche vergebens. Diese Art über die Worker-Klasse war bislang der erste Versuch der Funktioniert hat, aus dem laufenden Subthread im Mainthread anzutriggern.