Loading promoted subclass from Qt Designer results in TypeError
Question:
I’m using Qt Designer and trying to promote a subclass QLabel
. I created a ui.file and tried to load it with the individual Label. The code (main.py
file) looks like this:
from PyQt5.QtWidgets import *
from PyQt5 import uic
import os
import sys
class MyDialog(QDialog):
def __init__(self):
super(MyDialog, self).__init__()
uic.loadUi(os.path.join(basedir, "gui", "Test.ui"))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyDragDropWindow()
window.setGeometry(800, 100, 1000, 800)
window.show()
sys.exit(app.exec_())
The corresponding code of MyLabel
is:
from PyQt5.QtWidgets import *
class MyLabel(QLabel):
def __init__(self):
super(MyLabel).__init__()
When running the code, the following error occurs: TypeError: __init__() takes 1 positional argument but 2 were given
.
The promoting window looks like this:
The MyLabel
file is located in the MyWidgets
folder, which is in the same folder as the main.py
file.
This solution does not work.
Answers:
All QWidget based classes always accept a keyword argument for their parent, which defaults to None
.
The UI loader always creates widgets with their parent as argument.
While, for most situations, it’s normally enough to just declare the __init__
with a single "parent" positional argument, it’s considered best practice to always use the *args, **kwargs
signature for both the function definition and the super call (as long as the arguments respect the base class constructors).
class MyLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
In case you need custom arguments for dynamically created widgets, then you have different choices, considering that the first argument will always be the parent:
- define a specific signature, like
def __init__(self, parent, someArg, [...][, *args][, **kwargs]):
and then super().__init__(parent)
;
- (better) use keyworder/named arguments, and, in that case:
- if you declare named arguments, always use a default
parent=None
as first argument;
- pop other possible keyworded arguments from
kwargs
before calling the base implementation;
- use keyworded arguments for custom Qt properties through the
pyqtProperty
(Property
for PySide) decorator or function, but also remember that they will always be set in the super().__init__()
call, so if there’s anything that’s required to the processing of those arguments happens after that, you need to pop those values from kwargs
and eventually set the property afterwards;
Note: since Python 3, super()
doesn’t normally need any argument, but if you specify them, they have to be correct: super(MyLabel).__init__()
is wrong, as the instance must be declared along with the class in order to properly resolve the initialization: you either do super(MyLabel, self).__init__()
or you just use the default and normally suggested super().__init__()
.
I’m using Qt Designer and trying to promote a subclass QLabel
. I created a ui.file and tried to load it with the individual Label. The code (main.py
file) looks like this:
from PyQt5.QtWidgets import *
from PyQt5 import uic
import os
import sys
class MyDialog(QDialog):
def __init__(self):
super(MyDialog, self).__init__()
uic.loadUi(os.path.join(basedir, "gui", "Test.ui"))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyDragDropWindow()
window.setGeometry(800, 100, 1000, 800)
window.show()
sys.exit(app.exec_())
The corresponding code of MyLabel
is:
from PyQt5.QtWidgets import *
class MyLabel(QLabel):
def __init__(self):
super(MyLabel).__init__()
When running the code, the following error occurs: TypeError: __init__() takes 1 positional argument but 2 were given
.
The promoting window looks like this:
The MyLabel
file is located in the MyWidgets
folder, which is in the same folder as the main.py
file.
This solution does not work.
All QWidget based classes always accept a keyword argument for their parent, which defaults to None
.
The UI loader always creates widgets with their parent as argument.
While, for most situations, it’s normally enough to just declare the __init__
with a single "parent" positional argument, it’s considered best practice to always use the *args, **kwargs
signature for both the function definition and the super call (as long as the arguments respect the base class constructors).
class MyLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
In case you need custom arguments for dynamically created widgets, then you have different choices, considering that the first argument will always be the parent:
- define a specific signature, like
def __init__(self, parent, someArg, [...][, *args][, **kwargs]):
and thensuper().__init__(parent)
; - (better) use keyworder/named arguments, and, in that case:
- if you declare named arguments, always use a default
parent=None
as first argument; - pop other possible keyworded arguments from
kwargs
before calling the base implementation; - use keyworded arguments for custom Qt properties through the
pyqtProperty
(Property
for PySide) decorator or function, but also remember that they will always be set in thesuper().__init__()
call, so if there’s anything that’s required to the processing of those arguments happens after that, you need to pop those values fromkwargs
and eventually set the property afterwards;
- if you declare named arguments, always use a default
Note: since Python 3, super()
doesn’t normally need any argument, but if you specify them, they have to be correct: super(MyLabel).__init__()
is wrong, as the instance must be declared along with the class in order to properly resolve the initialization: you either do super(MyLabel, self).__init__()
or you just use the default and normally suggested super().__init__()
.