<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Python GUIs - inheritance</title><link href="https://www.pythonguis.com/" rel="alternate"/><link href="https://www.pythonguis.com/feeds/inheritance.tag.atom.xml" rel="self"/><id>https://www.pythonguis.com/</id><updated>2020-05-11T09:00:00+00:00</updated><subtitle>Create GUI applications with Python and Qt</subtitle><entry><title>Understanding .parent() vs. Parent Class in PyQt6 Custom Widgets — Why self.parent() doesn't mean what you think it means</title><link href="https://www.pythonguis.com/faq/parent-vs-parent-class-in-powerbar-example/" rel="alternate"/><published>2020-05-11T09:00:00+00:00</published><updated>2020-05-11T09:00:00+00:00</updated><author><name>Martin Fitzpatrick</name></author><id>tag:www.pythonguis.com,2020-05-11:/faq/parent-vs-parent-class-in-powerbar-example/</id><summary type="html">In a custom widget example, the &lt;code&gt;_Bar&lt;/code&gt; class uses &lt;code&gt;self.parent()&lt;/code&gt; to access a &lt;code&gt;QDial&lt;/code&gt; object defined in the &lt;code&gt;PowerBar&lt;/code&gt; class. But &lt;code&gt;_Bar&lt;/code&gt; inherits from &lt;code&gt;QWidget&lt;/code&gt; &amp;mdash; so shouldn't &lt;code&gt;self.parent()&lt;/code&gt; refer to &lt;code&gt;QWidget&lt;/code&gt;? What's going on here?</summary><content type="html">
            &lt;blockquote&gt;
&lt;p&gt;In a custom widget example, the &lt;code&gt;_Bar&lt;/code&gt; class uses &lt;code&gt;self.parent()&lt;/code&gt; to access a &lt;code&gt;QDial&lt;/code&gt; object defined in the &lt;code&gt;PowerBar&lt;/code&gt; class. But &lt;code&gt;_Bar&lt;/code&gt; inherits from &lt;code&gt;QWidget&lt;/code&gt; &amp;mdash; so shouldn't &lt;code&gt;self.parent()&lt;/code&gt; refer to &lt;code&gt;QWidget&lt;/code&gt;? What's going on here?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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 &lt;em&gt;parent classes&lt;/em&gt; (the class you inherit from). In Qt, &lt;code&gt;.parent()&lt;/code&gt; refers to something else entirely &amp;mdash; the &lt;em&gt;parent widget&lt;/em&gt; in Qt's object hierarchy. Let's look at both, side by side, so the difference is clear.&lt;/p&gt;
&lt;h2 id="python-inheritance-the-parent-class"&gt;Python Inheritance: The Parent Class&lt;/h2&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;from PyQt6.QtWidgets import QWidget

class _Bar(QWidget):
    pass
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here, &lt;code&gt;QWidget&lt;/code&gt; is the parent class of &lt;code&gt;_Bar&lt;/code&gt;. You access the parent class's methods through &lt;code&gt;super()&lt;/code&gt; &amp;mdash; for example, &lt;code&gt;super().__init__()&lt;/code&gt; calls &lt;code&gt;QWidget.__init__()&lt;/code&gt;. This is standard Python and has nothing to do with Qt specifically. If you need a refresher on how inheritance works, see our &lt;a href="https://www.pythonguis.com/tutorials/python-classes/"&gt;guide to Python classes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="qts-parent-child-relationship-parent"&gt;Qt's Parent-Child Relationship: &lt;code&gt;.parent()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Qt has its own concept of parent-child relationships, and it operates at the &lt;em&gt;instance&lt;/em&gt; level, not the &lt;em&gt;class&lt;/em&gt; level. When you create a widget and pass another widget as its parent, Qt establishes an ownership relationship between those two &lt;em&gt;objects&lt;/em&gt;.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;from PyQt6.QtWidgets import QApplication, QWidget, QLabel

app = QApplication([])

window = QWidget()
label = QLabel("Hello!", parent=window)

print(label.parent())  # &amp;lt;PyQt6.QtWidgets.QWidget object at ...&amp;gt; &amp;mdash; this is `window`
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here, &lt;code&gt;label.parent()&lt;/code&gt; returns &lt;code&gt;window&lt;/code&gt; &amp;mdash; the specific &lt;code&gt;QWidget&lt;/code&gt; &lt;em&gt;instance&lt;/em&gt; that owns the label. It does &lt;strong&gt;not&lt;/strong&gt; return &lt;code&gt;QLabel&lt;/code&gt;'s superclass (&lt;code&gt;QFrame&lt;/code&gt;), and it has nothing to do with class inheritance.&lt;/p&gt;
&lt;p&gt;The Qt parent is the &lt;em&gt;container widget&lt;/em&gt; &amp;mdash; the widget that this widget lives inside.&lt;/p&gt;
&lt;h2 id="how-this-works-in-a-custom-widget"&gt;How This Works in a Custom Widget&lt;/h2&gt;
&lt;p&gt;Let's look at a simplified version of the &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-creating-your-own-custom-widgets/"&gt;PowerBar custom widget example&lt;/a&gt; to see both concepts in action:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;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()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When &lt;code&gt;PowerBar.__init__&lt;/code&gt; runs, it creates &lt;code&gt;_Bar(self)&lt;/code&gt;. That &lt;code&gt;self&lt;/code&gt; is the &lt;code&gt;PowerBar&lt;/code&gt; instance, and it gets passed as the &lt;code&gt;parent&lt;/code&gt; argument to &lt;code&gt;_Bar.__init__&lt;/code&gt;. From that moment on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;super().__init__(parent)&lt;/code&gt; calls &lt;code&gt;QWidget.__init__()&lt;/code&gt; &amp;mdash; that's Python's class inheritance at work.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;self.parent()&lt;/code&gt; on the &lt;code&gt;_Bar&lt;/code&gt; instance returns the &lt;code&gt;PowerBar&lt;/code&gt; instance &amp;mdash; that's Qt's object hierarchy at work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because &lt;code&gt;self.parent()&lt;/code&gt; returns the &lt;code&gt;PowerBar&lt;/code&gt; instance, &lt;code&gt;_Bar&lt;/code&gt; can reach &lt;code&gt;self.parent().dial&lt;/code&gt; and read the dial's current value. The two widgets are connected through Qt's parent-child ownership, not through class inheritance.&lt;/p&gt;
&lt;h2 id="a-quick-comparison"&gt;A Quick Comparison&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Python Inheritance&lt;/th&gt;
&lt;th&gt;Qt Parent-Child&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What is it?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A class inherits behavior from another class&lt;/td&gt;
&lt;td&gt;A widget instance is owned by another widget instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How you set it up&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;class _Bar(QWidget)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_Bar(parent=self)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How you access it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;super()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;self.parent()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Relationship between&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Classes&lt;/td&gt;
&lt;td&gt;Object instances&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_Bar&lt;/code&gt; inherits from &lt;code&gt;QWidget&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A &lt;code&gt;_Bar&lt;/code&gt; instance is owned by a &lt;code&gt;PowerBar&lt;/code&gt; instance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="why-qt-has-parent-child-relationships"&gt;Why Qt Has Parent-Child Relationships&lt;/h2&gt;
&lt;p&gt;Qt uses the parent-child system for two practical reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Memory management.&lt;/strong&gt; When a parent widget is deleted, all its child widgets are automatically deleted too. This prevents memory leaks &amp;mdash; you don't have to manually clean up every label, button, and layout inside a window.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Layout and visibility.&lt;/strong&gt; 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 &amp;mdash; and it's closely related to how &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-layouts/"&gt;layouts&lt;/a&gt; arrange widgets within a window.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="complete-working-example"&gt;Complete Working Example&lt;/h2&gt;
&lt;p&gt;Here's a full example you can run that prints both the Python parent class and the Qt parent to make the distinction concrete:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;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 &amp;mdash; .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())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When you run this, the console output will show something like:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;Python parent class (via super): QWidget
Qt parent instance (via self.parent()): &amp;lt;__main__.PowerBar object at 0x...&amp;gt;
Qt parent type: &amp;lt;class '__main__.PowerBar'&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The Qt parent is the &lt;code&gt;PowerBar&lt;/code&gt; instance &amp;mdash; the widget that owns &lt;code&gt;_Bar&lt;/code&gt; &amp;mdash; while the Python parent class remains &lt;code&gt;QWidget&lt;/code&gt;. Two different relationships, two different meanings, sharing one unfortunately overloaded word.&lt;/p&gt;
&lt;p&gt;To understand more about how Qt widgets communicate with each other, take a look at our tutorial on &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-signals-slots-events/"&gt;signals, slots and events in PyQt6&lt;/a&gt;.&lt;/p&gt;
            &lt;p&gt;For an in-depth guide to building Python GUIs with PyQt6 see my book, &lt;a href="https://www.pythonguis.com/pyqt6-book/"&gt;Create GUI Applications with Python &amp; Qt6.&lt;/a&gt;&lt;/p&gt;
            </content><category term="pyqt6"/><category term="python"/><category term="widgets"/><category term="qt"/><category term="inheritance"/><category term="qt6"/></entry></feed>