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.
Related
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 was trying to write a slot that connects to different pyqt signals. What I still can't wrap my head around is the difference between the two decorators #pyqtSignature() and #pyqtSlot().
Example to connect to pyqt clicked signal of QPushButton which is inherited from QAbstractButton, I used the following syntax on_widgetName_signalName, when using #pyqtSignature(""):
#pyqtSignature("")
def on_bn_gpx_select_file_clicked(self):
"""
Run when QPushButton is pressed, or do something
"""
pass
Now when using #pyqtSlot()
#pyqtSlot()
def on_bn_gpx_select_file_clicked(self):
"""
Run when QPushButton is pressed, or do something
"""
pass
My question is, what is the difference between the two decorators and when should I use #pyqtSignature or #pyqtSlot()
Thanks
The pyqtSignature decorator is part of the old-style signal and slot syntax, which was replaced by the new-style signal and slot syntax in PyQt-4.5.
Both decorators serve the same purpose, which is to explicitly mark a python method as a Qt slot and specify a C++ signature for it (most commonly in order to select a particular overload). The only relevant difference between the two decorators is that pyqtSlot has a much more pythonic API.
There should never be any need to use pyqtSignature in new code - it is only really needed for backwards-compatibility.
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.
I have a dialog class that is inheriting a pyside-uic-generated python class but my problem is that it cannot be extended my adding another base class.
import sys
from PySide import QtGui
from mi_ui import Ui_Dialog
class Worker(object):
def __init__(self):
super(Worker, self).__init__()
self.data = 1
class MainDialog(QtGui.QDialog, Ui_Dialog, Worker):
def __init__(self):
super(MainDialog, self).__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dlg = MainDialog()
print dlg.data
dlg.show()
sys.exit(app.exec_())
When I try to extend MainDialog with Worker, super does not call the Worker's __init__ and the print dlg.data fails because "AttributeError: 'MainDialog' object has no attribute 'data'"
My only work around seems to ignore super and invoke each __init__ manually.
QtGui.QDialog.__init__(self)
Worker.__init__(self)
Is this my only solution?
This is for Python 2.7.
Multiple inheritance is tricky in python. The classes that you are inheriting from cannot have any conflicts if you want it to work perfectly. In most cases multiple inheritance with pyside does cause a conflict because everything inherits QObject giving identical variables and methods. Python doesn't know which one to inherit. The painting is another area for conflict. The other thing to consider is the order of the inheritance. I believe that python tries inheritance and init from left to right. So if you only want the init method for the QtGui.QDialog and the Worker (Ui_Dialog will probably conflict) then you might want to try.
class MainDialog(QtGui.QDialog, Worker, Ui_Dialog):
In python 3 you can call the super method a little differently.
class MainDialog(QtGui.QDialog, Worker, Ui_Dialog):
super().__init__()
I believe that the way you are calling the init for 2.7 is the correct way of doing things. Questions similar to this are all over the place. It is a common problem known as the Diamond problem. Python super method and calling alternatives may explain things a little more.
Make Worker the first base-class:
class MainDialog(Worker, QtGui.QDialog, Ui_Dialog)
This will still result in MainDialog.__init__ being called first, then Worker.__init__ (which can see if you add some print statements). But you will still be able to access the data attribute from inside the MainDialog.__init__.
The Ui_Dialog class doesn't really figure in any of this, because it is just an ordinary python class inheriting from object and doesn't ever call super. So it can go anywhere you like in the base-class order.
Obviously, if you do things this way, you will have to take care not to clobber any methods from the other base-classes in the Worker class - but you already had this "problem" anyway (just in a different order).
I am using PySide (Python Qt binding).
I have a worker thread of class QThread that updates the main GUI thread (updates the QTableWidget) through signal/slot mechanism.
In my worker thread, I have the following:
self.emit(SIGNAL("alterTable(object"), params)
In my GUI thread I have this:
self.connect(self.worker, SIGNAL("alterTable(object)"), self.updateMainTable, Qt.AutoConnection)
Since there are several similar worker threads running all connecting to the same slot (the self.updateMainTable), I should use the AutoConnection (and consequently the QueuedConnection). Using the Qt.DirectConnection works, but it is not safe (or so I have been told).
But when I try to use the AutoConnection, I get the following error:
QObject::connect: Cannot queue arguments of type 'object'
(Make sure 'object' is registered using qRegisterMetaType().)
I have Googled for eons trying to figure out a way how to use the qRegisterMetaType() in PySide, to no avail. All the resources I found online point to a C++ syntax/documentation.
If it makes any difference, the object in question is a dict most of the time.
I guess I have found an answer myself, well not exactly an answer, but a workable solution.
I switched all the Signals to the new-style syntax. In case anyone is wondering, I did that by defining a custom signal in my worker class. So my code looks something like this
class Worker(QThread):
alterTable = Signal(dict)
def __init__(self, parent=None):
....
self.alterTable.emit(parameters)
class GUI(QMainWindow):
def __init__(self, parent=None):
WorkerModule.Worker().alterTable.connect(self.myMethod)
For some reason the Signal has to be inside the QThread class; otherwise, Qt complains about "Signal has no attribute connect" error, which is very weird.
Incredibly late for the answer here, my apologies. Not enough reputation to add a comment to your accepted answer. I hope this might help new PySide/Pyside2 users who stumble upon your issue.
Issue: QObject::connect: Cannot queue arguments of type 'object'
Solution: self.connect(self.worker, SIGNAL("alterTable(PyObject)"), self.updateMainTable, Qt.AutoConnection)
Issue: Qt complains about "Signal has no attribute connect" error
Solution: The connect attribute is implemented in QObject, so you must first call the parent's init method through either QMainWindow.__init__(self) or super(GUI, self).__init__() (Py2) or also super().__init__() (Py3).
Cheers.