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:
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):
# 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:
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.
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:
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:
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:
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.
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:
- Design your window in Qt Designer and save the
.uifile. If you need to install Qt Designer separately, see our installation guide. - Convert it to Python with
pyuic6 -o mainwindow.py mainwindow.ui. - In your own
main.py, import the generated class. - Create a subclass that inherits from both the Qt widget class (e.g.
QMainWindow) and the generated UI class. - 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.
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!