Is it possible to write a PySide6 application without using .ui files or Qt Designer? How can I create widgets and lay out a window entirely in Python code?
Yes, absolutely. While Qt Designer is a helpful visual tool for building interfaces, you never need to use it. You can create every part of your GUI — windows, buttons, labels, layouts, and more — directly in Python. Many developers prefer working this way because it keeps everything in one place and gives you full control over your interface.
In this tutorial, we'll walk through building a PySide6 interface entirely in code, starting from a basic window and gradually adding widgets and layouts.
A minimal PySide6 window
Every PySide6 application needs two things: a QApplication instance, and at least one widget to display. Here's the simplest possible window:
import sys
from PySide6.QtWidgets import QApplication, QWidget
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("My App")
window.show()
app.exec()
Run this and you'll see an empty window with the title "My App". QWidget is the base class for all UI elements in Qt, and on its own it gives you a blank window to work with.
Adding a single widget
Let's add a button to the window. You can create any widget and place it inside your window by passing the window as the widget's parent:
import sys
from PySide6.QtWidgets import QApplication, QPushButton, QWidget
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("My App")
button = QPushButton("Click me!", window)
window.show()
app.exec()
The QPushButton is created with two arguments: the text to display, and the parent widget (window). This tells Qt that the button belongs inside the window.
This works, but the button just sits at position (0, 0) in the top-left corner. To arrange multiple widgets neatly, you'll want to use a layout.
Using layouts to arrange widgets
Layouts handle the positioning and resizing of widgets for you. Qt provides several layout types, including QVBoxLayout (vertical), QHBoxLayout (horizontal), and QGridLayout (grid-based).
Here's how to stack a few widgets vertically:
import sys
from PySide6.QtWidgets import (
QApplication, QLabel, QLineEdit, QPushButton,
QVBoxLayout, QWidget,
)
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("My App")
layout = QVBoxLayout()
layout.addWidget(QLabel("Enter your name:"))
layout.addWidget(QLineEdit())
layout.addWidget(QPushButton("Submit"))
window.setLayout(layout)
window.show()
app.exec()
Here we create a QVBoxLayout, add three widgets to it, and then apply the layout to the window with setLayout(). The layout takes care of stacking the label, text input, and button from top to bottom, and it will resize them sensibly if the user resizes the window.
Subclassing QWidget for your own windows
As your interface grows, putting everything at the top level of your script becomes hard to manage. The standard approach is to create your own window class by subclassing QWidget (or QMainWindow for more complex apps). This lets you set up the interface inside the __init__ method:
import sys
from PySide6.QtWidgets import (
QApplication, QLabel, QLineEdit, QPushButton,
QVBoxLayout, QWidget,
)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
layout = QVBoxLayout()
self.label = QLabel("Enter your name:")
layout.addWidget(self.label)
self.name_input = QLineEdit()
layout.addWidget(self.name_input)
self.submit_button = QPushButton("Submit")
layout.addWidget(self.submit_button)
self.setLayout(layout)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
By storing the widgets as attributes on self, you can refer to them later — for example, to read the text from the input field or to connect a button click to a function.
Connecting signals to make it interactive
Widgets in Qt communicate using signals and slots. When something happens — like a button being clicked — the widget emits a signal. You can connect that signal to any Python function to respond to the event.
Let's make the Submit button print a greeting:
import sys
from PySide6.QtWidgets import (
QApplication, QLabel, QLineEdit, QPushButton,
QVBoxLayout, QWidget,
)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
layout = QVBoxLayout()
self.label = QLabel("Enter your name:")
layout.addWidget(self.label)
self.name_input = QLineEdit()
layout.addWidget(self.name_input)
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.greet)
layout.addWidget(self.submit_button)
self.greeting_label = QLabel("")
layout.addWidget(self.greeting_label)
self.setLayout(layout)
def greet(self):
name = self.name_input.text()
self.greeting_label.setText(f"Hello, {name}!")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
The line self.submit_button.clicked.connect(self.greet) tells Qt: "When this button is clicked, call the greet method." Inside greet, we read the text from the input and update the greeting label. No .ui file needed — everything is wired up right here in Python.
Using QMainWindow for menus and status bars
If your application needs a menu bar, toolbars, or a status bar, you can subclass QMainWindow instead of QWidget. QMainWindow provides a built-in structure with these elements ready to use.
With QMainWindow, you place your content inside a central widget rather than setting a layout directly on the window:
import sys
from PySide6.QtWidgets import (
QApplication, QLabel, QLineEdit, QMainWindow,
QPushButton, QVBoxLayout, QWidget,
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
# Create a central widget and set it
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout()
central_widget.setLayout(layout)
self.label = QLabel("Enter your name:")
layout.addWidget(self.label)
self.name_input = QLineEdit()
layout.addWidget(self.name_input)
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.greet)
layout.addWidget(self.submit_button)
self.greeting_label = QLabel("")
layout.addWidget(self.greeting_label)
# Add a status bar message
self.statusBar().showMessage("Ready")
def greet(self):
name = self.name_input.text()
self.greeting_label.setText(f"Hello, {name}!")
self.statusBar().showMessage(f"Greeted {name}")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
The pattern is the same — create widgets, add them to a layout, connect signals — but now you also get a status bar at the bottom of the window for free.
Nesting layouts for complex interfaces
You can combine layouts to create more sophisticated designs. For example, you might have a horizontal layout inside a vertical layout to place two buttons side by side:
import sys
from PySide6.QtWidgets import (
QApplication, QHBoxLayout, QLabel, QLineEdit,
QPushButton, QVBoxLayout, QWidget,
)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
outer_layout = QVBoxLayout()
self.label = QLabel("Enter your name:")
outer_layout.addWidget(self.label)
self.name_input = QLineEdit()
outer_layout.addWidget(self.name_input)
# A horizontal row of buttons
button_layout = QHBoxLayout()
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.greet)
button_layout.addWidget(self.submit_button)
self.clear_button = QPushButton("Clear")
self.clear_button.clicked.connect(self.clear)
button_layout.addWidget(self.clear_button)
outer_layout.addLayout(button_layout)
self.greeting_label = QLabel("")
outer_layout.addWidget(self.greeting_label)
self.setLayout(outer_layout)
def greet(self):
name = self.name_input.text()
self.greeting_label.setText(f"Hello, {name}!")
def clear(self):
self.name_input.clear()
self.greeting_label.clear()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Notice that we use addLayout() (not addWidget()) to nest one layout inside another. You can combine QVBoxLayout, QHBoxLayout, and QGridLayout in any arrangement to build whatever interface you need.
Complete working example
Here's the final version bringing everything together — a QMainWindow with nested layouts, interactive widgets, and a status bar, all written in pure Python:
import sys
from PySide6.QtWidgets import (
QApplication, QHBoxLayout, QLabel, QLineEdit,
QMainWindow, QPushButton, QVBoxLayout, QWidget,
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Greeter App")
self.setMinimumWidth(300)
central_widget = QWidget()
self.setCentralWidget(central_widget)
outer_layout = QVBoxLayout()
central_widget.setLayout(outer_layout)
self.label = QLabel("Enter your name:")
outer_layout.addWidget(self.label)
self.name_input = QLineEdit()
self.name_input.setPlaceholderText("Your name here...")
outer_layout.addWidget(self.name_input)
button_layout = QHBoxLayout()
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.greet)
button_layout.addWidget(self.submit_button)
self.clear_button = QPushButton("Clear")
self.clear_button.clicked.connect(self.clear)
button_layout.addWidget(self.clear_button)
outer_layout.addLayout(button_layout)
self.greeting_label = QLabel("")
outer_layout.addWidget(self.greeting_label)
self.statusBar().showMessage("Ready")
def greet(self):
name = self.name_input.text()
if name:
self.greeting_label.setText(f"Hello, {name}!")
self.statusBar().showMessage(f"Greeted {name}")
else:
self.greeting_label.setText("Please enter a name.")
self.statusBar().showMessage("No name entered")
def clear(self):
self.name_input.clear()
self.greeting_label.clear()
self.statusBar().showMessage("Cleared")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Copy, paste, and run this file. You'll get a fully functional window with a text input, two buttons, a dynamic greeting label, and a status bar — all created without Qt Designer or any .ui files.
Everything you can do in Qt Designer, you can do in code. As your applications grow, you might find that building the interface programmatically makes it easier to manage, debug, and keep in version control alongside the rest of your Python code. To explore more of the available widgets, take a look at the PySide6 widgets tutorial.
Bring Your PyQt/PySide Application to Market
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.