I'm learning about signals and slots and I'm confused about this situation.
The context: I have a method in ClassA who needs to emit a signal (from the worker thread) to ClassB (in the main thread). The worker thread does some heavy duty processing, while the main thread updates a progress bar in the UI. I need the worker thread to pass signals to the main thread to update the UI.
I'm not sure how to have a signal be passed between two different classes. Right now I'm having the first class instantiate a signal object (Communicate), connect it to a method in the second class, and then emit when ready. This is causing a seg fault, so clearly I'm doing something wrong.
I have the following signal class:
class Communicate(QtCore.QObject):
update_progress = QtCore.Signal()
Here is the method in ClassA, the worker thread:
def methodInClassA(self, filename):
c = Communicate()
c.update_progress.connect(ClassB.set_progress)
print "emitting"
c.update_progress.emit()
...
Here is the method in ClassB, the one updating the progress bar in the UI:
class ClassB(QtGui.QDialog, classB.Ui_Dialog):
def __init__(self, parent=None):
super(ClassB, self).__init__(parent)
self.setupUi(self)
def set_progress(self):
print "RECEIVED"
sender = self.sender()
self.progressBar.setValue(100)
You are connecting c.update_progress to ClassB.set_progress, an unbound method. That doesn't work in PySide and I'm pretty sure it won't work in PyQt either. You need to have an instance of ClassB and connect c.update_progress to its set progress method, something like
c.update_progress.connect(i_am_b.set_progress)
i_am_b must have been instantiated elsewhere. You need to be careful to set the thread affinities for i_am_b and the instance of A before you call emit; see the docs for QObject.moveToThread.
Related
there's a design issue i have with a problem i'm currently working that will require a certain observable to emit values whenever it reaches a computation milestone,so i need values emitted intermediately,i discovered django implements something similar with signals which is just an implementation of the observer pattern but i really wanted to implement it the way django signals is implemented because observers subscribing to an observable( e.g after saving a model to the db i.e post_save signal) is very much decoupled in the sense that the observing function only needs to be annotated with the #receiver decorator.
So i took a look at django's source code and tried creating a simple version of the signal mechanism i created a signals class in one module with the decorator :
class Signal:
def __init__(self):
self.observers=[]
def connect(self,receiver):
self.observers.append(receiver.__name__)
def send(self,sender,**named):
return [
(receiver,mem_dec(signal=self,sender=sender,**named))
for receiver in self.observers
]
class Child(Signal):
def __init__(self):
super().__init__()
def mem_dec(signal,**kwargs):
def wrapper(func):
signal.connect(func, **kwargs)
return func
return wrapper
if __name__ == "__main__":
send_signal=Child()
send_signal.send(sender="class_child",a="henry")
and i placed the decorated function in another module to serve as the observer:
from .signals import mem_dec
from .signals import Child
#mem_dec(Child,sender=Child)
def hello(a,**kwargs):
print(f'hey {a}')
i noticed in my implementation doesn't work which i expected but the issue is that's what i could reproduce from the source code,i'm very confused about how they implemented their send() and connect() mechanism,all i want to achieve with this is for the signal subclass call all decorated functions, i made the Child class the signal and sender at the same time cause i'm just trying to reproduce the simplest example.
I have some questions about inheriting thread class.
class MyThread(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self)
self.num = num
def run(self):
print("Thread", self.num)
time.sleep(1)
why can't I only override the run method?
The Python document of threading mention that "The Thread class represents an activity that is run in a separate thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() method in a subclass."
Why does the above example code override the constructor also?
The constructor is overridden to pass the num parameter from the place where instance of MyThread is created to the run method.
Note that you do not call run method directly so you can't pass any parameters to it unless you store them in constructor.
If you don't need to pass parameters you can override only run method.
I need some help figuring out how to create a timer under a widget class. I've got the following class:
class TimerClass(QtGui.QWidget):
def __init__(self, parent = None):
super(TimerClass, self).__init__()
and I'm trying to implement a timer as follows:
def start_timer(self):
timer = QtCore.QTimer(self)
timer.timeout.connect(self.__Time)
timer.start(1000)
and it calls the following:
def __Time(self):
print("Timer End")
This QWidget is called from my MainWindow and I have another timer that works without a problem as shown above with MainWindow but I can't figure out how to get it to work with QWidget. I assume the use of QWidget is the problem because I get the following error when I try and run it:
AttributeError: 'MainWindow' object has no attribute '_TimerClass__Time'
Can anyone tell me what I'm doing wrong or what the proper way of doing this would be?
The only way to get that error from the code you've posted, is if the MainWindow class inherits the TimerClass, and then an instance of MainWindow tries to call self.__Time().
That cannot work, because double-underscored attributes are only directly accessible to the class that defines them. If you rename the method to have only one underscore, the error will go away.
However, using multiple inheritance with QObject subclasses (such as QWidget) is generally a bad idea, and should be avoided. Use delegation instead.
I spent the last hour(s???) looking/googling for a way to have a class start one of its methods in a new thread as soon as it is instanciated.
I could run something like this:
x = myClass()
def updater():
while True:
x.update()
sleep(0.01)
update_thread = Thread(target=updater)
update_thread.daemon = True
update_thread.start()
A more elegant way would be to have the class doing it in init when it is instanciated.
Imagine having 10 instances of that class...
Until now I couldn't find a (working) solution for this problem...
The actual class is a timer and the method is an update method that updates all the counter's variables. As this class also has to run functions at a given time it is important that the time updates won't be blocked by the main thread.
Any help is much appreciated. Thx in advance...
You can subclass directly from Thread in this specific case
from threading import Thread
class MyClass(Thread):
def __init__(self, other, arguments, here):
super(MyClass, self).__init__()
self.daemon = True
self.cancelled = False
# do other initialization here
def run(self):
"""Overloaded Thread.run, runs the update
method once per every 10 milliseconds."""
while not self.cancelled:
self.update()
sleep(0.01)
def cancel(self):
"""End this timer thread"""
self.cancelled = True
def update(self):
"""Update the counters"""
pass
my_class_instance = MyClass()
# explicit start is better than implicit start in constructor
my_class_instance.start()
# you can kill the thread with
my_class_instance.cancel()
In order to run a function (or memberfunction) in a thread, use this:
th = Thread(target=some_func)
th.daemon = True
th.start()
Comparing this with deriving from Thread, it has the advantage that you don't export all of Thread's public functions as own public functions. Actually, you don't even need to write a class to use this code, self.function or global_function are both equally usable as target here.
I'd also consider using a context manager to start/stop the thread, otherwise the thread might stay alive longer than necessary, leading to resource leaks and errors on shutdown. Since you're putting this into a class, start the thread in __enter__ and join with it in __exit__.
I'm using pyqt4.
I have a class multi inherited from QObject and QRunnable like this:
class DownloadTask(QObject, QRunnable):
def __init__(self):
QObject.__init__(self)
QRunnable.__init__(self)
self.setAutoDelete(False)
When an instance of DownloadTask is initializing, the last line throws exception:
TypeError: could not convert 'DownloadTask' to 'QRunnable'
But I think it is correct in grammer, QRunnable has the method setAutoDelete. Why can't it convert to QRunnable?
Update:
I intend to use QThreadPool to manage multi threads downloading resources from Internet, and emit a signal after finished. How can I do that?
PyQt reference guide > Things to be Aware Of > Multiple inheritance:
It is not possible to define a new Python class that sub-classes from more than one Qt class.