I created a custom QPushButton subclass and set its size and stylesheet, but nothing happens — the button doesn't appear in my window. I'm using a UI built with Qt Designer. Why can't the button be set to a size and other styles?
If you've designed a window in Qt Designer and then tried to add a custom widget in your Python code, you may have run into a frustrating situation: the widget just doesn't show up, and none of your size or style settings seem to have any effect.
The reason comes down to how widgets are displayed in a Qt application. Let's walk through what's going wrong and how to fix it.
The problem: a widget without a home
Here's a simplified version of the code that causes this issue:
from PyQt6.QtWidgets import QApplication, QPushButton, QWidget
from PyQt6.QtCore import QSize
import sys
class MyButton(QPushButton):
def __init__(self):
super().__init__()
self.setStyleSheet("background:green")
self.setFixedSize(QSize(100, 20))
class Demo(QWidget):
def __init__(self):
super().__init__()
self.resize(345, 225)
self.btn = MyButton()
self.btn.setFixedSize(QSize(100, 20))
if __name__ == "__main__":
app = QApplication([])
w = Demo()
w.show()
sys.exit(app.exec())
If you run this, you'll see an empty window. The MyButton exists in memory, but it has no connection to the Demo widget. In Qt, every widget needs to know where it belongs — either by being given a parent widget, or by being placed into a layout that is attached to a parent.
When you create MyButton() without passing a parent, Qt treats it as a top-level window of its own. It won't appear inside your Demo widget because Qt has no reason to put it there.
The fix: give the widget a parent or add it to a layout
There are two straightforward ways to make your custom button appear inside your window.
Pass the parent widget
You can pass self (the parent window) when creating the button:
self.btn = MyButton(parent=self)
You'll also need to update your MyButton.__init__ to accept and forward the parent:
class MyButton(QPushButton):
def __init__(self, parent=None):
super().__init__(parent)
self.setStyleSheet("background:green")
self.setFixedSize(QSize(100, 20))
This will make the button appear, but it will be positioned at the top-left corner of the window (position 0, 0) by default. You'd need to manually call self.btn.move(x, y) to position it, which is fragile and doesn't adapt well to window resizing.
Bring Your PyQt/PySide Application to Market — Specialized launch support for scientific and engineering software built using Python & Qt.
Using Layouts
The better approach is to use a layout. Layouts automatically manage the position and size of child widgets, and they handle resizing gracefully.
from PyQt6.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout
from PyQt6.QtCore import QSize
import sys
class MyButton(QPushButton):
def __init__(self, parent=None):
super().__init__(parent)
self.setStyleSheet("background:green")
self.setFixedSize(QSize(100, 20))
class Demo(QWidget):
def __init__(self):
super().__init__()
self.resize(345, 225)
self.btn = MyButton()
layout = QVBoxLayout()
layout.addWidget(self.btn)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication([])
w = Demo()
w.show()
sys.exit(app.exec())
When you add a widget to a layout, the layout takes care of parenting automatically. The button now appears inside the window, with its green background and fixed size intact.
What about Qt Designer code?
When you use Qt Designer and export a .ui file (or convert it to Python code), the generated setupUi method creates widgets and adds them to layouts for you. In the original question, setupUi creates a QPushButton called self.pushButton — that's the button you see in the window.
The custom MyButton created afterward in __init__ is a completely separate widget. It has no relationship to the button that Qt Designer placed, and since it was never added to the window's layout or given the window as a parent, it simply doesn't appear.
Here's the original setupUi code adapted for PyQt6, with the bug highlighted:
from PyQt6.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout
from PyQt6.QtCore import QSize, QRect, QMetaObject
import sys
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(345, 225)
self.pushButton = QPushButton(Form)
self.pushButton.setGeometry(QRect(20, 30, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton.setText("PushButt")
QMetaObject.connectSlotsByName(Form)
class MyButton(QPushButton):
def __init__(self, parent=None):
super().__init__(parent)
self.setStyleSheet("background:green")
self.setFixedSize(QSize(100, 20))
class Demo(Ui_Form, QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
# This button is created but never added to the window!
self.btn = MyButton()
self.btn.setFixedSize(QSize(100, 20))
if __name__ == "__main__":
app = QApplication([])
w = Demo()
w.show()
sys.exit(app.exec())
The self.pushButton created by setupUi shows up fine because it's given Form (which is self, the window) as its parent. But self.btn = MyButton() creates a floating, parentless widget.
Fixing it with Qt Designer code
To add your custom button alongside the Designer-generated UI, you need to integrate it into the window. The cleanest way is to add a layout to your Designer form and then insert the custom widget into it from your Python code.
Here's a complete working example that places both the Designer button and the custom button into a layout:
from PyQt6.QtWidgets import (
QApplication, QPushButton, QWidget, QVBoxLayout
)
from PyQt6.QtCore import QSize
import sys
class MyButton(QPushButton):
def __init__(self, text="", parent=None):
super().__init__(text, parent)
self.setStyleSheet("background: green; color: white;")
self.setFixedSize(QSize(100, 30))
class Demo(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Form")
self.resize(345, 225)
# The original button from the Designer form
self.push_button = QPushButton("PushButt")
# Your custom button, now part of the same window
self.btn = MyButton("My Button")
# A layout to hold both buttons
layout = QVBoxLayout()
layout.addWidget(self.push_button)
layout.addWidget(self.btn)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication([])
w = Demo()
w.show()
sys.exit(app.exec())
Both buttons now appear in the window. The MyButton instance respects its fixed size and green stylesheet because it's properly part of the widget hierarchy.
Using custom widgets directly in Qt Designer
If you want your custom widget class to appear inside Qt Designer itself — so you can drag and drop it like any other widget — you can use Qt Designer's widget promotion feature. This lets you tell Designer that a particular QPushButton on your form should actually be an instance of your MyButton class at runtime.
For a full walkthrough of this approach, see the tutorial on creating your own custom widgets.
Summary
When a widget doesn't respond to size or style changes, the most common cause is that it hasn't been added to the window. Always make sure your widgets are either:
- Given a parent widget when created, or
- Added to a layout that belongs to the parent window
Using layouts is the recommended approach, since they handle positioning and resizing automatically. And when working with Qt Designer, remember that the generated setupUi code creates its own widgets — any additional widgets you create in Python need to be explicitly added to the window's layout to appear.