I'm new to PyQt.
I'm trying to put a QTableView in a class, so I can define it's behaviour in the class without mixing it with all the other code, but when I do so it just won't show.
Here's the code i'm learning from. It was borrowed from [ Edit table in pyqt using QAbstractTableModel ]. Readapted it slightly to use with Qt5 and moved the QTableView in a class
import sys
from PyQt5 import QtGui, QtCore
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication, QVBoxLayout, QTableView, QWidget
from PyQt5.QtCore import *
# données à représenter
my_array = [['00','01','02'],
['10','11','12'],
['20','21','22']]
def main():
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
# création de la vue et du conteneur
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
tablemodel = MyTableModel(my_array, self)
table = Table(tablemodel)
layout = QVBoxLayout(self)
layout.addWidget(table)
self.setLayout(layout)
# création du modèle
class Table(QWidget):
def __init__(self, model):
super().__init__()
self.model = model
self.initUI()
def initUI(self):
self.setMinimumSize(300,300)
self.view = QTableView()
self.view.setModel(self.model)
class MyTableModel(QAbstractTableModel):
def __init__(self, datain, parent = None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.arraydata = datain
def rowCount(self, parent):
return len(self.arraydata)
def columnCount(self, parent):
return len(self.arraydata[0])
def data(self, index, role):
if not index.isValid():
return None
elif role != Qt.DisplayRole:
return None
return (self.arraydata[index.row()][index.column()])
"""
def setData(self, index, value):
self.arraydata[index.row()][index.column()] = value
return True
def flags(self, index):
return Qt.ItemIsEditable
"""
if __name__ == "__main__":
main()
If I remove the class and use
table = QTableView()
table.setModel(tablemodel)
the table shows no problem.
What am I missing?
the problem: table.view has no parent. If you add self.view.show() to test to Table.initUi(), you get two widgets, MyWindow with empty table as tmoreau wrote and table.view as isolated widget.
You can either pass a parent when constructing table.view in Table.initUi()
self.view = QTableView(self)
(then you don't need a layout) or add table.view to a layout as written by tmoreau, Then the tableview is reparented.
Removing the class has the same effect, then the tableview is added to layout.
You defined Tableas a QWidget with an attribute self.view=QTableView.
But you didn't define a layout on Table, so it will be displayed as an empty widget.
You either have to define a layout for Table, and add the view to it, or directly add the view to the main window's layout:
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
tablemodel = MyTableModel(my_array, self)
table = Table(tablemodel)
layout = QVBoxLayout(self)
layout.addWidget(table.view) #add view instead of table
self.setLayout(layout)
A third way is to change the definition of Table: you could subclass QTableView instead of QWidget (code not tested):
class Table(QTableView):
def __init__(self, model, parent):
super(Table,self).__init__(parent)
self.setMinimumSize(300,300)
self.setModel(model)
Related
I would like to add a column of checkbox to my qtableview. I need the checkboxes to be in the center of column (i.e. aligned center). I have this example which works fine, BUT the checkboxes are aligned left.
import sys
import pandas as pd
from PyQt5 import QtCore, Qt
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QCheckBox, QHBoxLayout, QItemDelegate, QTableView, QWidget, QApplication, QMainWindow
class MyCheckboxDelegate(QItemDelegate):
def __init__(self, parent):
QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
check = QCheckBox(parent)
check.clicked.connect(self.currentIndexChanged)
return check
def setModelData(self, editor, model, index):
model.setData(index, editor.checkState())
#pyqtSlot()
def stateChanged(self):
self.commitData.emit(self.sender())
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data):
super().__init__()
print(data)
self._data = data
def rowCount(self, index=None):
return self._data.shape[0]
def columnCount(self, parnet=None):
return self._data.shape[1]
def data(self, index, role=QtCore.Qt.DisplayRole):
if index.isValid():
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
if self._data.columns[index.column()]=='Delete':
return ''
value = self._data.iloc[index.row(), index.column()]
return str(value)
class MyWindow(QMainWindow):
def __init__(self, *args):
QWidget.__init__(self, *args)
table_model = TableModel(pd.DataFrame([['', ''], ['','']]))
self.table_view = QTableView()
self.table_view.setModel(table_model)
self.table_view.setItemDelegateForColumn(0, MyCheckboxDelegate(self))
for row in range(0, table_model.rowCount()):
self.table_view.openPersistentEditor(table_model.index(row, 0))
self.setCentralWidget(self.table_view)
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
To force them to come at center, I create a widget, add a layout and add the check box to the layout. In other words, I change the createEditor function of MyCheckboxDelegate as follows:
def createEditor(self, parent, option, index):
w = QWidget(parent)
layout = QHBoxLayout(w)
check = QCheckBox(parent)
check.clicked.connect(self.currentIndexChanged)
check.setStyleSheet("color: red;")
layout.addWidget(check)
layout.setAlignment(Qt.AlignCenter)
return w
The problem is that now, the setModelData will not be called anymore. I need to access `model' after a checkbox is clicked.
Has anybody an idea how to fix it?
Item delegates are able to set model data as long as the editor has a user property, and a basic QWidget doesn't.
The solution is to create a QWidget subclass that implements that property, and connect the checkbox to a signal that will actually do the same as before:
class CenterCheckBox(QWidget):
toggled = pyqtSignal(bool)
def __init__(self, parent):
super().__init__(parent)
layout = QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
self.check = QCheckBox()
layout.addWidget(self.check, alignment=Qt.AlignCenter)
self.check.setFocusProxy(self)
self.check.toggled.connect(self.toggled)
# set a 0 spacing to avoid an empty margin due to the missing text
self.check.setStyleSheet('color: red; spacing: 0px;')
#pyqtProperty(bool, user=True) # note the user property parameter
def checkState(self):
return self.check.isChecked()
#checkState.setter
def checkState(self, state):
self.check.setChecked(state)
class MyCheckboxDelegate(QStyledItemDelegate):
def __init__(self, parent):
super().__init__(parent)
def createEditor(self, parent, option, index):
check = CenterCheckBox(parent)
check.toggled.connect(lambda: self.commitData.emit(check))
return check
def setModelData(self, editor, model, index):
model.setData(index, editor.checkState)
Note that:
it's usually better to use QStyledItemDelegate, which is more consistent with the overall application appearance;
you should always check the column (or row) before returning the editor and do the same (or at least check the editor) in setModelData(), or, alternatively, use setItemDelegateForColumn();
In the default behavior of editing a cell in a QtableView, when the user clicks away either to another widget or closes the form, the edits are lost. After a lot of googling, I have found a way to save the edits if the user selects another widget in the form, but if the form is closed, the edits are still lost. The blog post is here.
I attempted to call the closeEditor method from the forms closeEvent, but it requires two parameters: the editor and hint. I can provide QAbstractItemDelegate.NoHint but the editor is expecting the QlineEdit object where the editing is taking place. I am lost on how to provide this for the cell currently being edited.
Here is a gif of the current behaviour:
My question is how do I provide the QlineEdit of the cell being edited?
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
from PyQt5.QtWidgets import *
from phones import *
class Main(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.resize(490, 998)
self.layoutWidget = QWidget(self)
self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.new_phone = QtWidgets.QPushButton(self.layoutWidget)
self.new_phone.setObjectName("new_phone")
self.new_phone.setText("New Phone")
self.horizontalLayout_7.addWidget(self.new_phone)
self.delete_phone = QtWidgets.QPushButton(self.layoutWidget)
self.delete_phone.setObjectName("delete_phone")
self.delete_phone.setText("Delete phone")
self.horizontalLayout_7.addWidget(self.delete_phone)
self.verticalLayout.addLayout(self.horizontalLayout_7)
self.phone_view = Syn_tableview()
self.verticalLayout.addWidget(self.phone_view)
self.cont_id = '9'
self.setCentralWidget(self.layoutWidget)
self.new_phone.clicked.connect(self.add_phone)
self.populate_phones()
def populate_phones(self):
self.phone_model = QSqlTableModel(self)
self.phone_model.setTable("contact_phones")
self.phone_model.setFilter("contact_id='{0}'".format(self.cont_id))
self.phone_model.select()
self.phone_view.setModel(self.phone_model)
self.phone_view.resizeColumnsToContents()
def add_phone(self):
self.phone_model.submitAll()
self.phone_model.setEditStrategy(QSqlTableModel.OnManualSubmit)
row = self.phone_model.rowCount()
record = self.phone_model.record()
record.setGenerated('id', False) #primary key
record.setValue('contact_id', self.cont_id) #foreign key
self.phone_model.insertRecord(row, record)
phone_index_edit = self.phone_model.index(row, self.phone_model.fieldIndex('phone_number'))
self.phone_view.edit(phone_index_edit)
def closeEvent(self, event):
submit = self.phone_model.submitAll()
#This is the problem
self.phone_view.closeEditor("QLineEdit", QAbstractItemDelegate.NoHint)
class Syn_tableview(QTableView):
def __init__(self, *args, **kwargs):
QTableView.__init__(self, *args, **kwargs)
def closeEditor(self, editor, hint):
if hint == QAbstractItemDelegate.NoHint:
QTableView.closeEditor(self, editor,
QAbstractItemDelegate.SubmitModelCache)
if __name__=="__main__":
app=QApplication(sys.argv)
db = QSqlDatabase.addDatabase("QPSQL");
db.setHostName(server)
db.setDatabaseName(database)
db.setUserName(user)
db.setPassword(pword)
myapp = Main()
myapp.show()
sys.exit(app.exec_())
The delegate editors are children of the QTableView so you can use findChildren to get them, to make sure they are not other children you can set an objectName that allows you to filter them:
import sys
from PyQt5 import QtCore, QtSql, QtWidgets
def create_connection():
db = QtSql.QSqlDatabase.addDatabase("QPSQL")
# FIXME
db.setHostName("server")
db.setDatabaseName("database")
db.setUserName("user")
db.setPassword("pword")
if not db.open():
print(db.lastError().text())
return False
return True
class Syn_Delegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = super(Syn_Delegate, self).createEditor(parent, option, index)
if isinstance(editor, QtWidgets.QWidget):
editor.setObjectName("syn_editor")
return editor
class Syn_Tableview(QtWidgets.QTableView):
def closeEditor(self, editor, hint):
if hint == QtWidgets.QAbstractItemDelegate.NoHint:
hint = QtWidgets.QAbstractItemDelegate.SubmitModelCache
super(Syn_Tableview, self).closeEditor(editor, hint)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.new_phone = QtWidgets.QPushButton(self.tr("New Phone"))
self.delete_phone = QtWidgets.QPushButton(self.tr("Delete phone"))
self.phone_view = Syn_Tableview()
self.phone_model = QtSql.QSqlTableModel()
self.phone_model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
self.phone_view.setModel(self.phone_model)
self.phone_view.resizeColumnsToContents()
delegate = Syn_Delegate(self)
self.phone_view.setItemDelegate(delegate)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QGridLayout(central_widget)
lay.addWidget(self.new_phone, 0, 0)
lay.addWidget(self.delete_phone, 0, 1)
lay.addWidget(self.phone_view, 1, 0, 1, 2)
self._contact_id = "9"
self.populate_phones()
self.new_phone.clicked.connect(self.add_phone)
#property
def contact_id(self):
return self._contact_id
def populate_phones(self):
self.phone_model.setTable("contact_phones")
self.phone_model.setFilter("contact_id='{0}'".format(self.contact_id))
self.phone_model.select()
#QtCore.pyqtSlot()
def add_phone(self):
self.phone_model.submitAll()
row = self.phone_model.rowCount()
record = self.phone_model.record()
record.setGenerated("id", False) # primary key
record.setValue("contact_id", self.contact_id) # foreign key
self.phone_model.insertRecord(row, record)
phone_index_edit = self.phone_model.index(
row, self.phone_model.fieldIndex("phone_number")
)
if phone_index_edit.isValid():
self.phone_view.edit(phone_index_edit)
def closeEvent(self, event):
for editor in self.phone_view.findChildren(QtWidgets.QWidget, "syn_editor"):
self.phone_view.commitData(editor)
submit = self.phone_model.submitAll()
super().closeEvent(event)
def main():
app = QtWidgets.QApplication(sys.argv)
if not create_connection():
sys.exit(-1)
w = MainWindow()
w.show()
w.resize(640, 480)
ret = sys.exit(app.exec_())
sys.exit(ret)
if __name__ == "__main__":
main()
I am using PyQt5 and quite new to it. I would like to drag and drop a QListWidgetItem from one QListWidget to the other, such that the resulting QListWidgetItem on one side will contain additional data. I tried sub-classing QListWidgetItem, but the type does not carry through drag and drop as it seems to create a new instance of QListWidgetItem.
Here is the code:
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout, QListWidget, QListWidgetItem, QAction, QVBoxLayout
from PyQt5 import QtCore, QtGui
import sys
class GUI(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.central_widget = MyCentralWidget(self)
self.setCentralWidget(self.central_widget)
class MyCustomItem(QListWidgetItem):
def __init__(self, data, *args, **kwargs):
super().__init__(*args, **kwargs)
self.extra_data = data
class MyCentralWidget(QWidget):
def __init__(self, parent):
super(MyCentralWidget, self).__init__(parent)
self.h_layout = QHBoxLayout(self)
self.setLayout(self.h_layout)
self.list_left = DragAndDropList()
self.list_left.setDragEnabled(True)
self.list_left.setAcceptDrops(False)
self.list_right = DragAndDropList()
self.h_layout.addWidget(self.list_left)
self.h_layout.addWidget(self.list_right)
item = MyCustomItem(69, 'custom_item')
self.list_left.insertItem(1, item)
class DragAndDropList(QListWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setIconSize(QtCore.QSize(124, 124))
self.setDragDropMode(self.DragDrop)
self.setSelectionMode(self.ExtendedSelection)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
super().dragEnterEvent(event)
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
else:
super().dragMoveEvent(event)
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
links.append(str(url.toLocalFile()))
self.emit(QtCore.SIGNAL("dropped"), links)
else:
event.setDropAction(QtCore.Qt.LinkAction)
super().dropEvent(event)
list_items = [self.item(i) for i in range(self.count())]
for l in list_items:
print(l.extra_data)
def main():
app = QApplication([])
win = GUI()
win.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Here I get the error: "AttributeError: 'QListWidgetItem' object has no attribute 'extra_data'", when I try to drag and drop the custom_item.
I did have look at this thread [1], but it is out of date and there were no clear solutions.
Subclassing QListWidgetItem won't help you, as the drag and drop data is always serialized, which means that no instance reference is ever exchanged.
If your data is serializable (strings, obviously, but usually any QVariant type is fine, such as QColor or QPixmap), you can just use QListWidgetItem.setData() with a custom role specific for every data field you want to store, and then use QListWidgetItem.data() to get that data back.
In this case I created a custom function, but that's obviously not necessary, as you can just manually set the data for each item before or after inserting it, as long as you have the right row index.
MySpecialRole = QtCore.Qt.UserRole + 1
class DragAndDropList(QtWidgets.QListWidget):
def addCustomItem(self, name, data):
item = QtWidgets.QListWidgetItem(name)
item.setData(MySpecialRole, data)
self.addItem(item)
def dropEvent(self, event):
super().dropEvent(event)
# let's see the data for each item, including our custom role
for row in range(self.count()):
item = self.item(row)
print('Data for item {}: {}'.format(
row + 1, item.data(MySpecialRole)))
class MyCentralWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyCentralWidget, self).__init__(parent)
self.h_layout = QtWidgets.QHBoxLayout(self)
self.setLayout(self.h_layout)
self.list_left = DragAndDropList()
self.list_left.setDragEnabled(True)
self.list_right = DragAndDropList()
self.list_right.setAcceptDrops(True)
self.h_layout.addWidget(self.list_left)
self.h_layout.addWidget(self.list_right)
self.list_left.addCustomItem('item (using addCustomItem)', 'some data')
self.list_left.addItem('item without custom data')
self.list_left.addItem('this item will have data')
self.list_left.item(2).setData(MySpecialRole, 'some custom data')
Note that the following line will give you an error:
self.emit(QtCore.SIGNAL("dropped"), links)
Not only the list widget doesn't have an emit attribute (like any other subclass of QObject doesn't), but also custom signals have to be declared in the class definition and then emitted directly.
class DragAndDropList(QtWidgets.QListWidget):
dropped = QtCore.pyqtSignal(object)
def dropEvent(self, event):
# ...
self.dropped.emit(links)
How does one use a QFileSystemModel to populate several QComboBox with subdirectories?
I have built a project management tool that allows me to create and manage my projects. I am currently using a combination of os.listdir and json to populate and validate my QComboboxes. But I am trying to learn a more modelview approach with QFileSystemModel.
So this is what I have:
class FileSystemModel(QW.QFileSystemModel):
def __init__(self, root, parent=None):
QW.QFileSystemModel.__init__(self, parent)
self.root = root
self.rootIndex = self.setRootPath(root)
class Window(QW.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__()
self.init()
def init(self):
layout = QW.QVBoxLayout()
self.cbox = QW.QComboBox()
self.cbox2 = QW.QComboBox()
self.model = FileSystemModel("C:\\projects\\")
self.cbox.setModel(self.model)
self.cbox2.setModel(self.model)
self.cbox.setRootModelIndex(self.model.rootIndex)
self.cbox.currentIndexChanged.connect(self._indexChanged)
layout.addWidget(self.cbox)
layout.addWidget(self.cbox2)
self.setLayout(layout)
def _indexChanged(self):
row = self.sender().currentIndex()
index = self.sender().rootModelIndex().child(row, 0)
self.cbox2.setRootModelIndex(index)
def main():
app = QW.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
I was attempting to repopulate the cbox2 using the index from cbox, but with my code it doesn't seem to work - it just stays empty.
Okay here is modified version of what you had:
from sys import exit as sysExit
from PyQt5.QtCore import QDir, pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QFileSystemModel, QHBoxLayout, QComboBox
class SysDirModel(QFileSystemModel):
def __init__(self, DirPath):
QFileSystemModel.__init__(self)
self.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
self.setReadOnly(True)
# Property
self.setRootPath(DirPath)
# Property
self.RootIndex = self.index(DirPath)
class SysFileModel(QFileSystemModel):
def __init__(self, DirPath):
QFileSystemModel.__init__(self)
self.setFilter(QDir.NoDotAndDotDot | QDir.Files)
self.setReadOnly(True)
# Property
self.setRootPath(DirPath)
# Property
self.RootIndex = self.index(DirPath)
def ResetPath(self, DirPath):
self.setRootPath(DirPath)
self.RootIndex = self.index(DirPath)
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setGeometry(150, 150, 450, 100)
# If you use forward slash this works in Windows as well and it is cleaner
self.SysDirs = SysDirModel('C:/projects/')
self.SysFils = SysFileModel('C:/projects/')
# Setup first ComboBox
self.cbxDirs = QComboBox()
self.cbxDirs.setMinimumWidth(200)
self.cbxDirs.setModel(self.SysDirs)
self.cbxDirs.setRootModelIndex(self.SysDirs.RootIndex)
# This sends a Signal to a predefined Slot
self.cbxDirs.currentIndexChanged.connect(self.IndexChanged)
self.cbxFiles = QComboBox()
self.cbxFiles.setMinimumWidth(200)
self.cbxFiles.setModel(self.SysFils)
self.cbxFiles.setRootModelIndex(self.SysFils.RootIndex)
HBox = QHBoxLayout()
HBox.addWidget(self.cbxDirs)
HBox.addStretch(1)
HBox.addWidget(self.cbxFiles)
self.setLayout(HBox)
# This is the receiver of a Signal (aka Slot) so it ought to be used as such
#pyqtSlot(int)
def IndexChanged(self, RowIdx):
# Get your Current DirPath based on the Selected Value
index = self.cbxDirs.rootModelIndex().child(RowIdx, 0)
DirPath = self.cbxDirs.model().filePath(index)
# Reset what ComboBox 2's Model and what it is looking at
self.cbxFiles.clear()
self.SysFils.ResetPath(DirPath)
self.cbxFiles.setModel(self.SysFils)
if __name__ == '__main__':
MainThred = QApplication([])
MainGui = MainWindow()
MainGui.show()
sysExit(MainThred.exec_())
I am lost with all the parenting/initialising issues and have no idea why this does not work.
So I create a Label, then I create another Label with some painting in it, them I make a widget that contains the two, then I would like to put this new widget inside the main window... but nothing appears
import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Labhtml(QLabel):
def __init__(self):
super().__init__()
label = QLabel('html')
class Bar(QLabel):
def __init__(self):
super().__init__()
self.resize(100, 5)
def paintEvent(self, e):
qp = QPainter(self)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(0,0,200,3)
class Wid(QWidget):
def __init__(self, parent):
super().__init__(parent=parent)
widget = QWidget()
html = Labhtml()
bar = Bar()
self.layout = QVBoxLayout(widget)
self.layout.addWidget(html)
self.layout.addWidget(bar)
class Example(QScrollArea):
def __init__(self):
super().__init__()
widget = QWidget()
layout = QVBoxLayout(widget)
layout.addWidget(Wid(widget))
self.setWidget(widget)
self.setWidgetResizable(True)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
First for the class Labhtml, when you inherit from QLabel, you can use the methods and the attributes of the base class, or use the instantiation mechanism to pass some parameters :
class Labhtml(QLabel):
def __init__(self):
super().__init__()
self.setText('html')
Then you don't need to create another widget inside the Wid class, but you have to refer to self instead :
class Wid(QWidget):
def __init__(self, parent):
super().__init__(parent=parent)
html = Labhtml()
bar = Bar()
self.layout = QVBoxLayout(self)
self.layout.addWidget(html)
self.layout.addWidget(bar)
About the instantiation mechanism you could also write the classes by declaring a new text argument (the same used for the Qlabel), and pass it when you create your instance :
class Labhtml(QLabel):
def __init__(self, text):
super().__init__(text)
class Wid(QWidget):
def __init__(self, parent):
super().__init__(parent=parent)
html = Labhtml('html')