Page 1 of 2 12 LastLast
Results 1 to 20 of 26

Thread: Main thread - worker thread communication.

  1. #1
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Main thread - worker thread communication.

    Hi to all and great for me to be here!

    I was previously used to C# and delegates to communicate from Main Form's thread with a worker thread that i spawn from that form and now i use Python and Qt and trying to do the same thing.
    I have the very simple example of counting from "start" to "end" and just display the progress in a progress bar.
    The routine that does that is running on a secondary thread. I have made the Gui with Qt Designer and i have the following code that i wrote:

    Qt Code:
    1. import sys
    2. import threading
    3. from PyQt4 import QtCore, QtGui
    4. from calculatorform_ui import Ui_CalculatorForm
    5. from ui_countNumbers import Ui_MainWindow
    6. from time import sleep
    7.  
    8. class CountNumbersForm(QtGui.QMainWindow):
    9. def __init__(self, parent=None):
    10. QtGui.QMainWindow.__init__(self, parent)
    11. self.ui = Ui_MainWindow()
    12. self.ui.setupUi(self)
    13.  
    14. @QtCore.pyqtSignature("")
    15. def on_start_clicked(self):
    16. t = threading.Thread(self.doCount())
    17. t.start()
    18.  
    19. def doCount(self):
    20. start = self.ui.spFrom.value()
    21. end = self.ui.spTo.value() + 1
    22.  
    23. for x in range(start, end):
    24. self.ui.progres.setValue(x)
    25. sleep(1)
    26. app.processEvents()
    27.  
    28. if __name__ == "__main__":
    29. app = QtGui.QApplication(sys.argv)
    30. count = CountNumbersForm();
    31. count.show()
    32. sys.exit(app.exec_())
    To copy to clipboard, switch view to plain text mode 

    (spFrom and spTo are spin boxes, "start" is a button that to press to do the job)


    Apart from the fact that progress bar does not updated correctly (it stops updating at some percent and not at 100%), my main problem is that main thread (ie. the main Form) is not so responsive as i thought it would be.
    I read somewhere that Qt's Signals and Slots mechanism is working correctly in the cross-thread situation but apparently i have made something wrong and thus program hase that behavior.

    Can anyone please help me with this ? How can i reliably communicate from Form's main thread to it's working thread in Qt ?

    Thanks a lot for any help!

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    You're not using signals and slots here. First of all you should use Qt threads instead of Python threads, otherwise there is a good chance it won't work properly.

    In run() method of the thread create an object that inherits QObject and there declare a signal which you then have to emit each time you want to change the progress bar value. Then connect the signal to the setValue slot in the progress bar and start the thread. And forget about processEvents() - you don't need it.

  3. #3
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    You're not using signals and slots here. First of all you should use Qt threads instead of Python threads, otherwise there is a good chance it won't work properly.
    But i thought that i used Signals and Slots...Isn't the declaration "def on_start_clicked(self):" just an alternative way to the usual "QtCore.QObject.connect" call ?
    I mean, the Signals and Slots mechanism is underneath of both ways, isn't ??

    In run() method of the thread create an object that inherits QObject and there declare a signal which you then have to emit each time you want to change the progress bar value. Then connect the signal to the setValue slot in the progress bar and start the thread.
    Ok, i will try right know this and i let you know. Should i implement a QThread instead of a Python one ??

    And forget about processEvents() - you don't need it.
    Ok, i just did (forgot)
    Software Engineer, riding a Kona King Kikapu 2007

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    Yes, provided that start is a button. Yes, you should use QThreads.

  5. #5
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    You're not using signals and slots here. First of all you should use Qt threads instead of Python threads, otherwise there is a good chance it won't work properly.

    In run() method of the thread create an object that inherits QObject and there declare a signal which you then have to emit each time you want to change the progress bar value. Then connect the signal to the setValue slot in the progress bar and start the thread. And forget about processEvents() - you don't need it.
    At first, a million thanks for helping me out...

    So, i am not sure i am following here..
    Do you mean to do something like this:

    Qt Code:
    1. class ProgressNotifier(QObject):
    2. def __init__(self, start, end):
    3. self.start = start
    4. self.end = end
    5.  
    6. def notify(self):
    7. # declare signal here
    8.  
    9. class CountNumbersForm(QtGui.QMainWindow):
    10. def __init__(self, parent=None):
    11. QtGui.QMainWindow.__init__(self, parent)
    12. self.ui = Ui_MainWindow()
    13. self.ui.setupUi(self)
    14.  
    15. @QtCore.pyqtSignature("")
    16. def on_start_clicked(self):
    17. pn = ProgressNotifier(self.ui.spFrom.value(), self.ui.spTo.value() + 1);
    18. # connect the signal here (the method of pn) to the progress bar "setValue" slot
    19. t = threading.Thread(self.doCount())
    20. t.start()
    21.  
    22. def doCount(self):
    23. for x in range(start, end):
    24. #emit signal so "setValue
    25. sleep(1)
    To copy to clipboard, switch view to plain text mode 

    If not, then how can i code it correctly ??
    If yes, why i need a second class to do this ??

    Again, a million thanks...
    Software Engineer, riding a Kona King Kikapu 2007

  6. #6
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by kikapu View Post
    But i thought that i used Signals and Slots...Isn't the declaration "def on_start_clicked(self):" just an alternative way to the usual "QtCore.QObject.connect" call ?
    I mean, the Signals and Slots mechanism is underneath of both ways, isn't ??
    Connecting Signals and Slots
    J-P Nurmi

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    You're still not using QThread.

  8. #8
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    You're still not using QThread.
    I think the main "problem" is not if i use or not QThread, i will certainly use it if you say that i have to. The main thing is if my skeleton code that i wrote is correct!
    Is it ??


    @jpn: Thanks, i already have this guide, i'll check it again.
    Software Engineer, riding a Kona King Kikapu 2007

  9. #9
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Ok, i read some docs and came up with something like the below. I like the postEvent/customEvent thing although i surely try to make an example with directly use the signals/slots mechanism.

    But i have the error "TypeError: 'int' object is not callable" at "t.start()" line...
    Can anyone help with this ?

    The code is:
    Qt Code:
    1. import sys
    2. from PyQt4 import QtCore, QtGui
    3. from calculatorform_ui import Ui_CalculatorForm
    4. from ui_countNumbers import Ui_MainWindow
    5. from time import sleep
    6.  
    7. class WorkerThread(QtCore.QThread):
    8. def __init__(self, start, end, receiver):
    9. QtCore.QThread.__init__(self)
    10. self.receiver = receiver
    11. self.start = start
    12. self.end = end
    13.  
    14. def run(self):
    15. for x in range(start, end):
    16. #sleep(1)
    17. event = QCustomEvent(200)
    18. event.setData(x)
    19. QThread.postEvent(self.receiver, event)
    20.  
    21. class CountNumbersForm(QtGui.QMainWindow):
    22. def __init__(self, parent=None):
    23. QtGui.QMainWindow.__init__(self, parent)
    24. self.ui = Ui_MainWindow()
    25. self.ui.setupUi(self)
    26.  
    27. @QtCore.pyqtSignature("")
    28. def on_start_clicked(self):
    29. t = WorkerThread(self.ui.spFrom.value(), self.ui.spTo.value() + 1, self);
    30. t.start()
    31.  
    32. def customEvent(self, event):
    33. if event.type() == 200:
    34. i = event.data()
    35. self.ui.progres.setValue(i)
    36.  
    37. if __name__ == "__main__":
    38. app = QtGui.QApplication(sys.argv)
    39. count = CountNumbersForm();
    40. count.show()
    41. sys.exit(app.exec_())
    To copy to clipboard, switch view to plain text mode 


    Thanks a lot for any help...
    Software Engineer, riding a Kona King Kikapu 2007

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    We won't know unless you implement the thread. The thread needs to emit a signal that will update the progress bar. I don't see that in your code.

  11. #11
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    We won't know unless you implement the thread. The thread needs to emit a signal that will update the progress bar. I don't see that in your code.
    Xmm,...ok, i do this now. But, isn't the postEvent/customEvent thing a viable mechanism to do such things ??
    Software Engineer, riding a Kona King Kikapu 2007

  12. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    You can use custom events but using signals is simpler. They use the event mechanism behind the scenes, so the result is the same, just less coding.

  13. #13
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    You can use custom events but using signals is simpler. They use the event mechanism behind the scenes, so the result is the same, just less coding.
    Ok the...I try to make it your way and i post the revised code below. I get the same error message as before: "TypeError: 'int' object is not callable" at t.start() line.

    here is the code:

    Qt Code:
    1. import sys
    2. from PyQt4 import QtCore, QtGui
    3. from calculatorform_ui import Ui_CalculatorForm
    4. from ui_countNumbers import Ui_MainWindow
    5. from time import sleep
    6.  
    7. class WorkerThread(QtCore.QThread):
    8. def __init__(self, form, start, end):
    9. QtCore.QThread.__init__(self)
    10. self.start = start
    11. self.end = end
    12. self.form = form
    13.  
    14. def run(self):
    15. c = C()
    16. QtCore.QObject.connect(form.ui.progressBar, c.update, form, QtCore.SLOT("setValue(int)"))
    17.  
    18. for x in range(start, end):
    19. c.emit(c.update, x)
    20.  
    21. class C(QtCore.QObject):
    22. update = QtCore.SIGNAL("update(int)")
    23.  
    24.  
    25. class CountNumbersForm(QtGui.QMainWindow):
    26. def __init__(self, parent=None):
    27. QtGui.QMainWindow.__init__(self, parent)
    28. self.ui = Ui_MainWindow()
    29. self.ui.setupUi(self)
    30.  
    31. @QtCore.pyqtSignature("")
    32. def on_start_clicked(self):
    33. t = WorkerThread(self, self.ui.spFrom.value(), self.ui.spTo.value() + 1);
    34. t.start()
    To copy to clipboard, switch view to plain text mode 

    I am very much frustrated here...
    Software Engineer, riding a Kona King Kikapu 2007

  14. #14
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    After a lot of study, i now coded it more correctly (i think) but strangely enough i get the same error message as before. ('int' object is not callable" at t.start() )

    Code is:

    Qt Code:
    1. import sys
    2. from PyQt4 import QtCore, QtGui
    3. from calculatorform_ui import Ui_CalculatorForm
    4. from ui_countNumbers import Ui_MainWindow
    5. from time import sleep
    6.  
    7. class WorkerThread(QtCore.QThread):
    8. def __init__(self, start, end):
    9. QtCore.QThread.__init__(self)
    10. self.start = start
    11. self.end = end
    12.  
    13. def run(self):
    14. for x in range(start, end):
    15. self.emit(QtCore.SIGNAL("updateProgress"), x)
    16.  
    17.  
    18. class CountNumbersForm(QtGui.QMainWindow):
    19. def __init__(self, parent=None):
    20. QtGui.QMainWindow.__init__(self, parent)
    21. self.ui = Ui_MainWindow()
    22. self.ui.setupUi(self)
    23.  
    24. @QtCore.pyqtSignature("")
    25. def on_start_clicked(self):
    26. worker = WorkerThread(self.ui.spFrom.value(), self.ui.spTo.value() + 1);
    27. QtCore.QObject.connect(worker, QtCore.SIGNAL("updateProgress"), self.updateProgress, QtCore.Qt.QueuedConnection)
    28. worker.start()
    29.  
    30. def updateProgress(self, val):
    31. self.ui.progres.setValue(val)
    32.  
    33.  
    34. if __name__ == "__main__":
    35. app = QtGui.QApplication(sys.argv)
    36. count = CountNumbersForm();
    37. count.show()
    38. sys.exit(app.exec_())
    To copy to clipboard, switch view to plain text mode 
    Software Engineer, riding a Kona King Kikapu 2007

  15. #15
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    What is class C?

    I can give you a draft of C++ code that does what you want. Then you can translate it into python, as my python skills are a bit stale...

    Qt Code:
    1. class Emiter : public QObject {
    2. Q_OBJECT
    3. public:
    4. Emiter(QObject *parent=0) : QObject(parent){}
    5. void emitSignal(int v){ emit sig(v); }
    6. signals:
    7. void sig(int);
    8. };
    9. class MyThread : public QThread {
    10. Q_OBJECT
    11. public:
    12. MyThread(QObject *parent =0) : QThread(parent){}
    13. void run() {
    14. Emiter e;
    15. connect(&e, SIGNAL(sig(int)), this, SIGNAL(propagate(int)));
    16. i=0;
    17. while(i<=100){
    18. sleep(1);
    19. e.emitSignal(i++);
    20. }
    21. }
    22. signals:
    23. void propagate(int);
    24. };
    25.  
    26. //...
    27. MyThread thread;
    28. connect(&thread, SIGNAL(propagate(int)), &pbar, SLOT(setValue(int)));
    29. thread.start();
    To copy to clipboard, switch view to plain text mode 
    Of course there are other ways to do the same thing, for example the propagate() signal is not needed, you can connect the original signal directly to the progress bar if you have access to it.

  16. #16
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    What is class C?
    There is no class C anymore (see my just above post for a more correct solution). Ok, i try to translate your C code although i think that the last Python version i posted is very much alike...
    Software Engineer, riding a Kona King Kikapu 2007

  17. #17
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    The code you posted is dangerous because you emit a signal from a worker thread on account of an object that is in the gui thread and I have no idea in context of which thread the signal will be emitted and will it be queued or executed directly. My Emiter class makes sure the context of the worker thread is used and the signal is queued and propagated in the context of the GUI thread.

  18. #18
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    The code you posted is dangerous because you emit a signal from a worker thread on account of an object that is in the gui thread
    But isn't the whole idea ?? In C# we use delegates to do that, in Qt i hoped that with Signals and Slots i will be able to do it. I think that Qt automatically find the correct thread to "use".

    Your Emiter class is "translated" to Python like this ?
    Qt Code:
    1. class Emiter(QtCore.QObject):
    2. def __init__(self):
    3. QObject.__init__(self)
    4.  
    5. def emitSignal(self, val):
    6. self.emit(QtCore.SIGNAL("updateProgress"), x)
    To copy to clipboard, switch view to plain text mode 

    And what is the purpose (and implementation as it is not shown how it does it's work) of MyThread:: propagate ? Just to forward the signal ?

    I think i am stuck...
    Last edited by kikapu; 22nd May 2007 at 15:35.
    Software Engineer, riding a Kona King Kikapu 2007

  19. #19
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by kikapu View Post
    But isn't the whole idea ?? In C# we use delegates to do that, in Qt i hoped that with Signals and Slots i will be able to do it. I think that Qt automatically find the correct thread to "use".
    Yes, but I'm not sure what it will decide when you call a function from an object that lives in another thread. It might work, but I'm not sure, therefore I used this kind of "proxy".

    Your Emiter class is "translated" to Python like this ?
    Qt Code:
    1. class Emiter(QtCore.QObject):
    2. def __init__(self):
    3. QObject.__init__(self)
    4.  
    5. def emitSignal(self, val):
    6. self.emit(QtCore.SIGNAL("updateProgress"), x)
    To copy to clipboard, switch view to plain text mode 
    Looks correct.


    And what is the purpose (and implementation as it is not shown how it does it's work) of MyThread:: propagate ? Just to forward the signal ?
    Yes, just to forward the signal. As I mentioned, you could do it without it, but then you'd have to have access to the progress bar from within the thread object. That's your choice.

  20. #20
    Join Date
    May 2007
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Main thread - worker thread communication.

    Quote Originally Posted by wysota View Post
    Yes, just to forward the signal. As I mentioned, you could do it without it, but then you'd have to have access to the progress bar from within the thread object. That's your choice.
    Yes, i now what you mean, we sometimes use it in .net too. But i am afraid i can not go too far, every solution that i implement, i see this error "TypeError: 'int' object is not callable"

    I really feel like an idiot, i have written countless thousands lines of code in my life and i am stucked in 10 lines of this. What can i say...
    Software Engineer, riding a Kona King Kikapu 2007

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.