Emit is delayed
-
I have a program written in python that has a QT interface. I am using python 3's threading library and time.sleep and getting the following errors:
- QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
- QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
- QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
- QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
In order to address this error I tried to define a QThread class to substitute. But the signal I am emitting does not connect to the receiver and only executes as the thread is exiting. This signal should be emit with each iteration of the loop in get_web_query, but instead it only appears when the get_web_query function exits. Please advise.
#!/usr/bin/python3 #WebQueryModule.py import sys, os, time, inspect sys.path.insert(0, '../') import web_query, search from PyQt5.QtWidgets import QApplication from PyQt5.QtCore import pyqtSignal, pyqtSlot, QThread class WebQueryThread(QThread): done_signal = pyqtSignal(str) def __init__(self): QThread.__init__(self) def run(self): self.search_web_query() self.done_signal.emit('WebQueryThread done_signal') def search_web_query(self): name = inspect.currentframe().f_code.co_name print(name) try: if web_query.INTERTHREAD_SIGNAL: web_query.main() except Exception as e: print(sys.exc_info()) class WebQueryResultThread(QThread): new_web_output = pyqtSignal(list) def __init__(self): QThread.__init__(self) def run(self): self.new_web_output.emit(['test','testing']) self.get_web_query() def new_web_query_output(self): name = inspect.currentframe().f_code.co_name new_web_query_output = next(web_query.get_output()).split('\n') return new_web_query_output def get_web_query(self): name = inspect.currentframe().f_code.co_name while web_query.INTERTHREAD_SIGNAL: o = self.new_web_query_output() print(name, o) self.new_web_output.emit(o) time.sleep(1) print('Exiting get_web_query') def process_done_signal(result): print(result) sys.exit() @pyqtSlot() def process_new_web_output(output): print('new web output') # MyMainWindow.web_query_handler(output) if __name__ == '__main__': app = QApplication(sys.argv) thread = WebQueryThread() thread.done_signal.connect(process_done_signal) thread.start() thread2 = WebQueryResultThread() thread2.new_web_output.connect(process_new_web_output) thread2.start() time.sleep(5) # This will continue to run forever, except we are killing the app # in the process_done_signal() function. print('Signal to close...') web_query.INTERTHREAD_SIGNAL = False sys.exit(app.exec_())
Output looks like this:
get_web_query ['']
Exiting get_web_query
search_web_query
main doing search
get_web_query ['search_term: abwenden', '']
Exiting get_web_query
get_web_query ['search_term: abwenden', 'Translating: abwenden', 'sich [ von jdm / etw ] abwenden to turn away [ from sb / sth ] ', '']
Exiting get_web_query
get_web_query ['search_term: abwenden', 'Translating: abwenden', 'sich [ von jdm / etw ] abwenden to turn away [ from sb / sth ] ', '']
Exiting get_web_query
get_web_query ['search_term: abwenden', 'Translating: abwenden', 'sich [ von jdm / etw ] abwenden to turn away [ from sb / sth ] ', '']
Exiting get_web_query
Signal to close...
new web output
new web output
new web output
new web output
new web output
new web output
Exiting web_query.main
WebQueryThread done_signal -
The issue lies between the connection type (defaulted to AutoConnection in PyQt - https://www.riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html?highlight=Qt.AutoConnection), and the sleep(5) between starting the threads, and invoking app.exec_(). Removing the sleep to allow the main thread's event loop to process the metacall events might result in interleaved output. That's up to the thread scheduler.
Switching to DirectConnection will definitely interleave output. This might not be appropriate, as the slots will be invoked within the WebQueryThread and WebQueryResultThread.
-
@jeremy_k Thank you very much for the advice. The clues provided did allow me to track down this:
So I added Qt::DirectConnection and this now is caught when the button is pressed.
Please don't do that! That causes your your slot to run in the GUI thread instead of your Algorithm's thread.
The answer appears to be in that thread.