In a custom widget example, the
_Barclass usesself.parent()to access aQDialobject defined in thePowerBarclass. But_Barinherits fromQWidget— so shouldn'tself.parent()refer toQWidget? What's going on here?
This is one of those moments where two completely different concepts share similar names, and it can trip you up if you're not expecting it. In Python, we talk about parent classes (the class you inherit from). In Qt, .parent() refers to something else entirely — the parent widget in Qt's object hierarchy. Let's look at both, side by side, so the difference is clear.
Python Inheritance: The Parent Class
When you create a class that inherits from another class, the class you inherit from is sometimes called the "parent class" or "superclass." For example:
from PyQt6.QtWidgets import QWidget
class _Bar(QWidget):
pass
Here, QWidget is the parent class of _Bar. You access the parent class's methods through super() — for example, super().__init__() calls QWidget.__init__(). This is standard Python and has nothing to do with Qt specifically. If you need a refresher on how inheritance works, see our guide to Python classes.
Qt's Parent-Child Relationship: .parent()
Qt has its own concept of parent-child relationships, and it operates at the instance level, not the class level. When you create a widget and pass another widget as its parent, Qt establishes an ownership relationship between those two objects.
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
app = QApplication([])
window = QWidget()
label = QLabel("Hello!", parent=window)
print(label.parent()) # <PyQt6.QtWidgets.QWidget object at ...> — this is `window`
Here, label.parent() returns window — the specific QWidget instance that owns the label. It does not return QLabel's superclass (QFrame), and it has nothing to do with class inheritance.
The Qt parent is the container widget — the widget that this widget lives inside.
How This Works in a Custom Widget
Let's look at a simplified version of the PowerBar custom widget example to see both concepts in action:
from PyQt6.QtWidgets import QApplication, QWidget, QDial, QVBoxLayout
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPainter, QColor
class _Bar(QWidget):
"""A custom bar display widget."""
def __init__(self, parent=None):
super().__init__(parent) # Python parent class: QWidget
# At this point, self.parent() returns whatever `parent` was passed in.
def paintEvent(self, event):
painter = QPainter(self)
# Access the dial value from the Qt parent widget
parent = self.parent() # Qt parent: the PowerBar instance
value = parent.dial.value()
painter.fillRect(0, 0, int(self.width() * value / 100), self.height(), QColor("green"))
painter.end()
class PowerBar(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout(self)
# _Bar is created with `self` as its Qt parent
self.bar = _Bar(self)
self.bar.setFixedHeight(30)
layout.addWidget(self.bar)
self.dial = QDial()
self.dial.setRange(0, 100)
self.dial.valueChanged.connect(self.bar.update)
layout.addWidget(self.dial)
app = QApplication([])
window = PowerBar()
window.show()
app.exec()
When PowerBar.__init__ runs, it creates _Bar(self). That self is the PowerBar instance, and it gets passed as the parent argument to _Bar.__init__. From that moment on:
Purchasing Power Parity
Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]super().__init__(parent)callsQWidget.__init__()— that's Python's class inheritance at work.self.parent()on the_Barinstance returns thePowerBarinstance — that's Qt's object hierarchy at work.
Because self.parent() returns the PowerBar instance, _Bar can reach self.parent().dial and read the dial's current value. The two widgets are connected through Qt's parent-child ownership, not through class inheritance.
A Quick Comparison
| Python Inheritance | Qt Parent-Child | |
|---|---|---|
| What is it? | A class inherits behavior from another class | A widget instance is owned by another widget instance |
| How you set it up | class _Bar(QWidget) |
_Bar(parent=self) |
| How you access it | super() |
self.parent() |
| Relationship between | Classes | Object instances |
| Example | _Bar inherits from QWidget |
A _Bar instance is owned by a PowerBar instance |
Why Qt Has Parent-Child Relationships
Qt uses the parent-child system for two practical reasons:
-
Memory management. When a parent widget is deleted, all its child widgets are automatically deleted too. This prevents memory leaks — you don't have to manually clean up every label, button, and layout inside a window.
-
Layout and visibility. Child widgets are drawn inside their parent. When you hide or move a parent widget, all its children go with it. This is how complex UIs stay organized — and it's closely related to how layouts arrange widgets within a window.
Complete Working Example
Here's a full example you can run that prints both the Python parent class and the Qt parent to make the distinction concrete:
import sys
from PyQt6.QtWidgets import (
QApplication, QWidget, QDial, QVBoxLayout, QLabel
)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPainter, QColor
class _Bar(QWidget):
"""A simple bar that reflects the dial's value."""
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedHeight(30)
# Show the difference
print(f"Python parent class (via super): QWidget")
print(f"Qt parent instance (via self.parent()): {self.parent()}")
print(f"Qt parent type: {type(self.parent())}")
def paintEvent(self, event):
painter = QPainter(self)
# Use the Qt parent to access sibling data
parent = self.parent()
if parent and hasattr(parent, "dial"):
value = parent.dial.value()
bar_width = int(self.width() * value / 100)
painter.fillRect(0, 0, bar_width, self.height(), QColor("#2ecc71"))
painter.end()
class PowerBar(QWidget):
"""A compound widget with a bar display and a dial control."""
def __init__(self):
super().__init__()
self.setWindowTitle("PowerBar — .parent() Demo")
layout = QVBoxLayout(self)
self.bar = _Bar(self) # `self` (PowerBar instance) becomes the Qt parent
layout.addWidget(self.bar)
self.dial = QDial()
self.dial.setRange(0, 100)
self.dial.setValue(25)
self.dial.valueChanged.connect(self.bar.update)
layout.addWidget(self.dial)
label = QLabel("Drag the dial to change the bar")
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(label)
app = QApplication(sys.argv)
window = PowerBar()
window.show()
sys.exit(app.exec())
When you run this, the console output will show something like:
Python parent class (via super): QWidget
Qt parent instance (via self.parent()): <__main__.PowerBar object at 0x...>
Qt parent type: <class '__main__.PowerBar'>
The Qt parent is the PowerBar instance — the widget that owns _Bar — while the Python parent class remains QWidget. Two different relationships, two different meanings, sharing one unfortunately overloaded word.
To understand more about how Qt widgets communicate with each other, take a look at our tutorial on signals, slots and events in PyQt6.
PyQt/PySide Development Services — Stuck in development hell? I'll help you get your project focused, finished and released. Benefit from years of practical experience releasing software with Python.