Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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.


Log in to reply