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.
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:
import sys from PyQt4 import QtCore, QtGui from calculatorform_ui import Ui_CalculatorForm from ui_countNumbers import Ui_MainWindow from time import sleep def __init__(self, form, start, end): self.start = start self.end = end self.form = form def run(self): c = C() for x in range(start, end): c.emit(c.update, x) update = QtCore.SIGNAL("update(int)") def __init__(self, parent=None): self.ui = Ui_MainWindow() self.ui.setupUi(self) @QtCore.pyqtSignature("") def on_start_clicked(self): t = WorkerThread(self, self.ui.spFrom.value(), self.ui.spTo.value() + 1); 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
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:
import sys from PyQt4 import QtCore, QtGui from calculatorform_ui import Ui_CalculatorForm from ui_countNumbers import Ui_MainWindow from time import sleep def __init__(self, start, end): self.start = start self.end = end def run(self): for x in range(start, end): self.emit(QtCore.SIGNAL("updateProgress"), x) def __init__(self, parent=None): self.ui = Ui_MainWindow() self.ui.setupUi(self) @QtCore.pyqtSignature("") def on_start_clicked(self): worker = WorkerThread(self.ui.spFrom.value(), self.ui.spTo.value() + 1); QtCore.QObject.connect(worker, QtCore.SIGNAL("updateProgress"), self.updateProgress, QtCore.Qt.QueuedConnection) worker.start() def updateProgress(self, val): self.ui.progres.setValue(val) if __name__ == "__main__": count = CountNumbersForm(); count.show() sys.exit(app.exec_())To copy to clipboard, switch view to plain text mode
Software Engineer, riding a Kona King Kikapu 2007
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...
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.Qt Code:
Q_OBJECT public: void emitSignal(int v){ emit sig(v); } signals: void sig(int); }; Q_OBJECT public: void run() { Emiter e; connect(&e, SIGNAL(sig(int)), this, SIGNAL(propagate(int))); i=0; while(i<=100){ sleep(1); e.emitSignal(i++); } } signals: void propagate(int); }; //... MyThread thread; QProgressBar pbar; connect(&thread, SIGNAL(propagate(int)), &pbar, SLOT(setValue(int))); thread.start();To copy to clipboard, switch view to plain text mode
Software Engineer, riding a Kona King Kikapu 2007
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.
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:
def __init__(self): def emitSignal(self, val): 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
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".
Looks correct.Your Emiter class is "translated" to Python like this ?
Qt Code:
def __init__(self): def emitSignal(self, val): self.emit(QtCore.SIGNAL("updateProgress"), x)To copy to clipboard, switch view to plain text mode
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.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, 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
Are you sure this is correct?
You have a variable called start and then you call start as a method. Try using a different name here. Maybe that's the problem.Qt Code:
def __init__(self, start, end): self.start = start self.end = endTo copy to clipboard, switch view to plain text mode
kikapu (22nd May 2007)
Software Engineer, riding a Kona King Kikapu 2007
I have made an exact (i hope) Python version of your C++ code, i post it below.
The thing seems to be working ok, the progress bar is updated correctly and the main thread (form) remains responsive.
(I do not like the fact that i use 3 classes just to do that but anyway...)
So, we connect the propagate SIGNAl to the Emiter one and thus we get the SLOT setValue of the progress bar to be fired when the SIGNAL is sent.
In a previous version of mine, you have said that in the way i had wrote it was a little dangerous because we might not be sure from what thread the code will be executed.
As i study more closely your code (and my Python implementation of this), what make you sure that in this way the function will be called from the correct thread ?
Here is the code:
Qt Code:
import sys from PyQt4 import QtCore, QtGui from calculatorform_ui import Ui_CalculatorForm from ui_countNumbers import Ui_MainWindow from time import sleep def __init__(self): def emitSignal(self, val): self.emit(QtCore.SIGNAL("updateProgress(int)"), val) def __init__(self): self.pstart = 0 self.pend = 0 def run(self): e = Emiter() propagate = QtCore.SIGNAL("propagate(int)") for x in range(self.pstart, self.pend): sleep(1) e.emitSignal(x) def __init__(self, parent=None): self.ui = Ui_MainWindow() self.ui.setupUi(self) @QtCore.pyqtSignature("") def on_start_clicked(self): worker.pstart = count.ui.spFrom.value() worker.pend = count.ui.spTo.value() + 1 self.ui.progress.setRange(worker.pstart, worker.pend) worker.start() def updateProgress(self, val): self.ui.progress.setValue(val) if __name__ == "__main__": count = CountNumbersForm(); worker = WorkerThread(); QtCore.QObject.connect(worker, QtCore.SIGNAL("propagate(int)"), count.ui.progress.setValue, QtCore.Qt.QueuedConnection) count.show() sys.exit(app.exec_())To copy to clipboard, switch view to plain text mode
I mean, if i emit entirely the Emit class and the like and replace WorkerThread class with this:
Qt Code:
def __init__(self): self.pstart = 0 self.pend = 0 def run(self): for x in range(self.pstart, self.pend): sleep(1) self.emit(QtCore.SIGNAL("updateProgress(int)"), x)To copy to clipboard, switch view to plain text mode
what do you think will go wrong ? I read PyQt4 docs and says that the mechanism is able to "Connections may be made across threads." Isn't it our occassion here and particularly because i use queued connections ?? (QtCore.Qt.QueuedConnection)
Thanks again!
Last edited by kikapu; 23rd May 2007 at 14:23.
Software Engineer, riding a Kona King Kikapu 2007
If you force queued connections, then all will be ok. The thing that makes me sure my approach will work is that the "emit" object is created (and thus handled) in the worker thread (because it's created in the run() method that is executed in context of the worker thread). This means that if I call a method that emits a signal and both the caller (run()) and the callee (Emit instance) are in the same (worker) thread, I can be sure that the signal will be queued because the receiver is in the GUI thread. Now if the callee (QThread object) was in a different thread than the caller (run()) I don't know how Qt would behave. You can check Qt sources and see for yourself - maybe the trick I made was not needed. You can also have the same effect without the Emit object - just move the QThread object to the thread it represents.
Bookmarks