Q&A: How to fix widgets appearing as separate windows?
Understanding Qt parents and layouts and the effect on widget position

Heads up! You've already completed this tutorial.

One very common issue when you start creating GUI applications with Python & Qt is having your widgets either disappear or start popping out of your interface as independent windows. This is pretty confusing if you don't understand why it happens, but once you do it's usually very easy to fix.

The key points --

  1. Any widget without a parent is a window. If you create a widget but don't set a parent it will become a separate window.
  2. Widgets without parents (i.e. any windows) are hidden by default and remain hidden until they are shown either by you, or automatically by Qt (for example when selecting tabs in a QTabWidget).
  3. Adding widgets to layouts sets their parent. Widgets not in layouts must have parents set explicitly.
  4. Removing a widget from a layout doesn't remove its parent.
  5. You can remove the parent from a widget by setting the parent to None. This will turn it into a window!

Below is a small example to demonstrate these effects. We create a window, add a layout and a widget.

python
import sys
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QApplication

class Window(QWidget):

    def __init__(self):
        super().__init__()

        # This is the widget that we will experiment with: note that we don't
        # set a parenet, and don't add it to the layout.
        self.mywidget = QLabel("Hello")
        self.mywidget.show()  # We need to show it (or focus it) to make it visible.

        add_parent = QPushButton("Add parent")
        add_parent.clicked.connect(self.add_parent)

        remove_parent = QPushButton("Remove parent")
        remove_parent.clicked.connect(self.remove_parent)

        add_layout = QPushButton("Add layout")
        add_layout.clicked.connect(self.add_layout)

        remove_layout = QPushButton("Remove layout")
        remove_layout.clicked.connect(self.remove_layout)

        self.vlayout = QVBoxLayout()

        self.vlayout.addWidget(add_parent)
        self.vlayout.addWidget(remove_parent)
        self.vlayout.addWidget(add_layout)
        self.vlayout.addWidget(remove_layout)

        self.setLayout(self.vlayout)

    def add_parent(self):
        self.mywidget.setParent(self)
        self.mywidget.move(0,0)
        self.mywidget.show()
        print("Added parent, parent is:", self.mywidget.parent())

    def remove_parent(self):
        self.mywidget.setParent(None)
        self.mywidget.show()
        print("Removed parent, parent is:", self.mywidget.parent())

    def add_layout(self):
        self.vlayout.addWidget(self.mywidget)
        print("Added layout, parent is:", self.mywidget.parent())

    def remove_layout(self):
        self.vlayout.removeWidget(self.mywidget)
        print("Removed layout, parent is:", self.mywidget.parent())

app = QApplication(sys.argv)

w = Window()
w.show()

app.exec()
python
import sys
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QApplication


class Window(QWidget):

    def __init__(self):
        super().__init__()

        # This is the widget that we will experiment with: note that we don't
        # set a parenet, and don't add it to the layout.
        self.mywidget = QLabel("Hello")
        self.mywidget.show()  # We need to show it (or focus it) to make it visible.

        add_parent = QPushButton("Add parent")
        add_parent.clicked.connect(self.add_parent)

        remove_parent = QPushButton("Remove parent")
        remove_parent.clicked.connect(self.remove_parent)

        add_layout = QPushButton("Add layout")
        add_layout.clicked.connect(self.add_layout)

        remove_layout = QPushButton("Remove layout")
        remove_layout.clicked.connect(self.remove_layout)

        self.vlayout = QVBoxLayout()

        self.vlayout.addWidget(add_parent)
        self.vlayout.addWidget(remove_parent)
        self.vlayout.addWidget(add_layout)
        self.vlayout.addWidget(remove_layout)

        self.setLayout(self.vlayout)

    def add_parent(self):
        self.mywidget.setParent(self)
        self.mywidget.move(0,0)
        self.mywidget.show()
        print("Added parent, parent is:", self.mywidget.parent())

    def remove_parent(self):
        self.mywidget.setParent(None)
        self.mywidget.show()
        print("Removed parent, parent is:", self.mywidget.parent())

    def add_layout(self):
        self.vlayout.addWidget(self.mywidget)
        print("Added layout, parent is:", self.mywidget.parent())

    def remove_layout(self):
        self.vlayout.removeWidget(self.mywidget)
        print("Removed layout, parent is:", self.mywidget.parent())


app = QApplication(sys.argv)

w = Window()
w.show()

app.exec()
python
import sys
from PySide2.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QApplication


class Window(QWidget):

    def __init__(self):
        super().__init__()

        # This is the widget that we will experiment with: note that we don't
        # set a parenet, and don't add it to the layout.
        self.mywidget = QLabel("Hello")
        self.mywidget.show()  # We need to show it (or focus it) to make it visible.

        add_parent = QPushButton("Add parent")
        add_parent.clicked.connect(self.add_parent)

        remove_parent = QPushButton("Remove parent")
        remove_parent.clicked.connect(self.remove_parent)

        add_layout = QPushButton("Add layout")
        add_layout.clicked.connect(self.add_layout)

        remove_layout = QPushButton("Remove layout")
        remove_layout.clicked.connect(self.remove_layout)

        self.vlayout = QVBoxLayout()

        self.vlayout.addWidget(add_parent)
        self.vlayout.addWidget(remove_parent)
        self.vlayout.addWidget(add_layout)
        self.vlayout.addWidget(remove_layout)

        self.setLayout(self.vlayout)

    def add_parent(self):
        self.mywidget.setParent(self)
        self.mywidget.move(0,0)
        self.mywidget.show()
        print("Added parent, parent is:", self.mywidget.parent())

    def remove_parent(self):
        self.mywidget.setParent(None)
        self.mywidget.show()
        print("Removed parent, parent is:", self.mywidget.parent())

    def add_layout(self):
        self.vlayout.addWidget(self.mywidget)
        print("Added layout, parent is:", self.mywidget.parent())

    def remove_layout(self):
        self.vlayout.removeWidget(self.mywidget)
        print("Removed layout, parent is:", self.mywidget.parent())

app = QApplication(sys.argv)

w = Window()
w.show()

app.exec_()
python
import sys
from PySide6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QApplication


class Window(QWidget):

    def __init__(self):
        super().__init__()

        # This is the widget that we will experiment with: note that we don't
        # set a parenet, and don't add it to the layout.
        self.mywidget = QLabel("Hello")
        self.mywidget.show()  # We need to show it (or focus it) to make it visible.

        add_parent = QPushButton("Add parent")
        add_parent.clicked.connect(self.add_parent)

        remove_parent = QPushButton("Remove parent")
        remove_parent.clicked.connect(self.remove_parent)

        add_layout = QPushButton("Add layout")
        add_layout.clicked.connect(self.add_layout)

        remove_layout = QPushButton("Remove layout")
        remove_layout.clicked.connect(self.remove_layout)

        self.vlayout = QVBoxLayout()

        self.vlayout.addWidget(add_parent)
        self.vlayout.addWidget(remove_parent)
        self.vlayout.addWidget(add_layout)
        self.vlayout.addWidget(remove_layout)

        self.setLayout(self.vlayout)

    def add_parent(self):
        self.mywidget.setParent(self)
        self.mywidget.move(0,0)
        self.mywidget.show()
        print("Added parent, parent is:", self.mywidget.parent())

    def remove_parent(self):
        self.mywidget.setParent(None)
        self.mywidget.show()
        print("Removed parent, parent is:", self.mywidget.parent())

    def add_layout(self):
        self.vlayout.addWidget(self.mywidget)
        print("Added layout, parent is:", self.mywidget.parent())

    def remove_layout(self):
        self.vlayout.removeWidget(self.mywidget)
        print("Removed layout, parent is:", self.mywidget.parent())

app = QApplication(sys.argv)

w = Window()
w.show()

app.exec_()

In the initial state the widget isn't added to any layout and has no parent, so when the application is run you'll actually see two floating windows. Push the control buttons to experiment with adding the widget to the layout, setting a parent, clearing the parent and removing it from the layout.

The starting view

Each time the state changes the current parent will be printed to the console. Notice that when you add the widget to the layout, the widget receives the Window as it's parent. This is the normal behavior in Qt: adding a widget to a layout will set it's parent to the widget on which the layout is applied (the container widget). In this case this is the Window itself.

python
Added layout, parent is: <__main__.Window(0x15413656090) at 0x000001542CB98688>

If you remove the widget from the layout, it's parent is not automatically cleared. The widget will remain inside the window, near it's original position. But the layout will re-lay the other items over it.

The widget is removed from the layout, but remains in place

If you remove the parent the widget will return to it's floating state.

Note that when setting the parent on the window we also call .move(0, 0) to move it to a specific point relative to the parent window. This is necessary to ensure we can see the widget: if you remove this, setting the parent will just make the widget disappear. If you have widgets disappearing in your apps, this is a good that they have a parent set but are not properly positioned or added to a layout. As a general rule, use layouts to avoid hitting these kinds of issues!

Over 10,000 developers have bought Create GUI Applications with Python & Qt!
Create GUI Applications with Python & Qt6
Take a look

Downloadable ebook (PDF, ePub) & Complete Source code

Also available from Leanpub and Amazon Paperback

[[ discount.discount_pc ]]% OFF for the next [[ discount.duration ]] [[discount.description ]] with the code [[ discount.coupon_code ]]

Purchasing Power Parity

Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]
Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Q&A: How to fix widgets appearing as separate windows? was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt.