Python Forum

Full Version: QThread Signal is emitted immediately at start of Code
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello, i have a Qestion again regarding QThreading. I wrote a very simple Sample Code for a Thread:

from PySide6 import QtCore
from PySide6.QtCore import Qt, Signal, QThread
import time

class MainThread(QThread):

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

	def run(self):

		print("MainThread started.")

		self.thread = Testthread()
		self.thread.print_1.connect(print("Output Text"))
		self.thread.start()
		self.thread.wait()

		print("MainThread ended.")

	def printtext(self, incoming):
		print("Func Fertig")
		print(incoming)
		
class Testthread(QThread):
	print_1 = Signal()

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

	def run(self):
		for x in range(1, 4):
			print("For-Loop A: "+str(x))
			time.sleep(1)
		self.print_1.emit() # Here it should emit to the Print-Function at this Point of the Code.
		self.func_2()

	def func_2(self):
		for x in range(1, 4):
			print("For-Loop B: "+str(x))
			time.sleep(1)
		print("Function 2 done.")
		self.quit()

if __name__ == "__main__":
	mainthread = MainThread()
	mainthread.run()
When i run this Code, the Output is:

MainThread started.
Output Text
For-Loop A: 1
For-Loop A: 2
For-Loop A: 3
For-Loop B: 1
For-Loop B: 2
For-Loop B: 3
Function 2 done.
MainThread ended.

But why is the "Output Text" Line outputted immediately at the beginning of the Code, where i connect the Slot to the Signal in the QThread Class?

I tried it with a Lambda Function: self.thread.print_1.connect(lambda: print("Output Text")). But in this Case nothing happens, there is no Output of the print Function.

My expected output should be:

MainThread started.
For-Loop A: 1
For-Loop A: 2
For-Loop A: 3
Output Text
For-Loop B: 1
For-Loop B: 2
For-Loop B: 3
Function 2 done.
MainThread ended.

because the Emit Function is called after the first For-Loop has endet. It should then Emit and Output the Print-Text and then continue with the second Loop in the Second Function in the Thread. But why it is not working here? What i am doing wrong here or do not understand?

Thank you very much and greetings,
Caliban
It prints because you call the print() function. Maybe you want to pass a function to the signal?
self.thread.print_1.connect(lambda: print("Output Text"))
Now the message is not printed indicating you have a problem with the print_1 signal.

I made an even simpler example to study the problem.
from PySide6 import QtCore


class MainThread(QtCore.QThread):
    def __init__(self):
        super().__init__()

    def run(self):
        print("start MainThread run")
        self.thread = TestThread()
        self.thread.print_1.connect(self.printit)
        self.thread.start()
        self.thread.wait()
        print("MainThread run finished.")

    def printit(self, msg):
        print("signal received")
        print(msg)


class TestThread(QtCore.QThread):
    print_1 = QtCore.Signal(str)

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

    def run(self):
        print("start TestThread run")
        self.print_1.emit("emitting signal")
        print("TestThread run finished")


if __name__ == "__main__":
    mainthread = MainThread()
    mainthread.run()
Output:
start MainThread run start TestThread run TestThread run finished MainThread run finished.
The output indicates the signal was not emitted or the emit failed to call the connected function.

Wondering if the problem has something to do with threads, I modified the MainThread run function.
    def run(self):
        print("start MainThread run")
        self.thread = TestThread()
        self.thread.print_1.connect(self.printit)
        # self.thread.start()
        # self.thread.wait()
        self.thread.run()
        print("MainThread run finished.")
Output:
start MainThread run start TestThread run signal received emitting signal TestThread run finished MainThread run finished.
Now that the signal emit is from the same thread as the connect, the emit works.

Armed with that info I searched for information about signals and threads. I found this in one of my favorite sources.

https://realpython.com/python-pyqt-qthre...-and-slots
Quote:A thread-safe object is an object that can be accessed concurrently by multiple threads and is guaranteed to be in a valid state. PyQt’s signals and slots are thread safe, so you can use them to establish interthread communication as well as to share data between threads.

You can connect signals emitted from a thread to slots within the thread or within a different thread. This means that you can execute code in a thread as a response to a signal emitted in the same thread or in another thread. This establishes a safe bridge of communication between threads.
So it should be possible to connect a signal in one thread to a slot in a different thread. I continued looking and came across this:

https://www.pythontutorial.net/pyqt/pyqt-qthread/
Quote:Note that another way of using the QThread class is to subclass it and override the run() method. However, it is not recommended way. Please find the detailed answer here.
The referenced link: https://stackoverflow.com/questions/5062...read-in-qt
Read the warning about subclassing QThread.
Thank you very much for your Answer and Help. I tried it on my Example and started the Thread with .run() instead of .start() and now it works. But i don't understand why this is the case? And i tried a little bit and noticed, when i run the Thread with .run(), other Signals like .started or .finished does not work anymore. I think it can be done with additional signals emitted.
If MainThread calls Tesrthread.run(), it is a regular function call, not a new thread.