Opening New Windows from Qt Designer Files in PyQt6

How to properly use Qt Designer generated UI files and open new windows with button clicks
Heads up! You've already completed this tutorial.

I designed my window in Qt Designer and converted it to a Python file. Now I want to open a new window when a button is clicked, but I can't figure out how to add custom behavior to the generated code. Copying and editing the generated class doesn't work. How do I properly open new windows when using Qt Designer-based files?

If you've been designing your UI in Qt Designer and then converting it to Python with pyuic, you've probably noticed that the generated code isn't really meant to be edited directly. There's even a warning at the top of the file that says so. But that leaves a real question: how do you add behavior — like opening a new window from a button click — without modifying that generated file?

The answer is to import the generated UI class into your own Python file and subclass it. This keeps your custom logic completely separate from the auto-generated code, so you can freely update your .ui file in Qt Designer without losing your work.

Let's walk through how to do this step by step.

Why you shouldn't edit the generated file

When you use pyuic6 (or the Qt Designer code generator) to convert a .ui file into Python, you get a class like Ui_MainWindow that sets up all your widgets. This file is meant to be regenerated every time you change the design. If you add your own code inside it — connecting signals, defining methods — all of that will be wiped out the next time you regenerate.

Instead, treat the generated file as a read-only resource. Import from it, and build on top of it in a separate file.

Setting up your project

Let's say you have a simple Qt Designer file with one button, and you've converted it to Python. Your project might look like this:

python
my_project/
├── mainwindow.py    # Generated by pyuic6 from your .ui file
└── main.py          # Your custom code goes here

The generated mainwindow.py file will contain something like this (you don't need to change it):

python
# Form implementation generated from reading ui file 'mainwindow.ui'
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.

from PyQt6 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(260, 226)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(90, 120, 75, 23))
        self.pushButton.setObjectName("pushButton")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 260, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))

Leave this file alone. All your custom work happens in main.py.

Importing and subclassing the UI

In your main.py file, you import the generated Ui_MainWindow class and create a new class that inherits from both QMainWindow and Ui_MainWindow. This technique is called multiple inheritance, and it gives your custom class all the widgets defined in Qt Designer plus the full power of a real QMainWindow.

Here's the basic pattern:

python
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from mainwindow import Ui_MainWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

By calling self.setupUi(self) inside __init__, all the widgets from your Qt Designer layout are created and attached to self. That means you can access self.pushButton (or whatever you named your widgets in Designer) directly in your class methods.

If you're new to working with Qt Designer in PyQt6, see our complete guide on using Qt Designer to design your GUI layout for a detailed walkthrough of the design-to-code workflow.

Connecting a button to open a new window

Now let's add the behavior you actually want: clicking a button to open a new window. You connect the button's clicked signal to a method that creates and shows a second window.

python
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from mainwindow import Ui_MainWindow


class SecondWindow(QMainWindow):
    """A simple second window."""
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Second Window")
        self.resize(300, 200)


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # Connect the button to our method
        self.pushButton.clicked.connect(self.open_new_window)

    def open_new_window(self):
        self.second_window = SecondWindow()
        self.second_window.show()


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

When you click the button, a new plain window appears. Notice that the second window is stored as self.second_window. This is important — if you used a local variable instead, Python's garbage collector would destroy the window immediately after the method finished, and you'd see it flash briefly (or not at all) before disappearing.

Using a second Qt Designer file for the new window

In a real application, you'll probably want to design the second window in Qt Designer too. The process is the same: design it, convert it with pyuic6, and then subclass it in your code.

Let's say you have a second generated file called secondwindow.py containing a class called Ui_SecondWindow. Your project now looks like this:

python
my_project/
├── mainwindow.py       # Generated from mainwindow.ui
├── secondwindow.py     # Generated from secondwindow.ui
└── main.py             # Your custom code

Here's how you bring it all together:

python
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from mainwindow import Ui_MainWindow
from secondwindow import Ui_SecondWindow


class SecondWindow(QMainWindow, Ui_SecondWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(self.open_new_window)

    def open_new_window(self):
        self.second_window = SecondWindow()
        self.second_window.show()


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Both windows are designed in Qt Designer, and all your custom logic lives safely in main.py. You can redesign either window and regenerate the .py files without touching your application code.

Opening another copy of the same window

If you want the button to open another instance of the same window design (using the same UI class), you can do that too. Just create a second class that inherits from the same generated UI:

python
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from mainwindow import Ui_MainWindow


class ChildWindow(QMainWindow, Ui_MainWindow):
    """A second window using the same Designer layout."""
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("Child Window")


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(self.open_new_window)

    def open_new_window(self):
        self.child_window = ChildWindow()
        self.child_window.show()


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

The ChildWindow class uses the exact same layout as MainWindow, but because it's a separate subclass you can customize its behavior independently — changing the title, disabling certain widgets, connecting different signals, and so on.

Opening multiple windows

With the code above, clicking the button repeatedly will replace self.second_window each time, which closes the previous one. If you want to keep multiple windows open at once, store them in a list. For a deeper look at managing multiple windows in PyQt6, see our tutorial on creating multiple windows.

python
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from mainwindow import Ui_MainWindow


class ChildWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("Child Window")


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        self.child_windows = []
        self.pushButton.clicked.connect(self.open_new_window)

    def open_new_window(self):
        child = ChildWindow()
        child.show()
        self.child_windows.append(child)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Each click now opens an additional window, and all of them stay open because they're all referenced in the list.

Summary

When working with Qt Designer-generated files, the golden rule is: don't edit them. Instead, import the UI classes into your own file and subclass them. This gives you full control over behavior while keeping your designs safe.

Here's the pattern at a glance:

  1. Design your window in Qt Designer and save the .ui file. If you need to install Qt Designer separately, see our installation guide.
  2. Convert it to Python with pyuic6 -o mainwindow.py mainwindow.ui.
  3. In your own main.py, import the generated class.
  4. Create a subclass that inherits from both the Qt widget class (e.g. QMainWindow) and the generated UI class.
  5. Call self.setupUi(self) in __init__, then add your custom connections and methods.

This approach scales well — whether you have two windows or twenty, each one can have its own Designer layout and its own custom subclass, all wired together cleanly in your application code.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Create GUI Applications with Python & Qt6 by Martin Fitzpatrick

(PyQt6 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!

More info Get the book

Martin Fitzpatrick

Opening New Windows from Qt Designer Files in PyQt6 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. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.