How to Center a Fixed-Size Widget in PyQt6 QMainWindow
Understanding Why setCentralWidget Places Your Widget in the Top-Left
When working with QMainWindow in PyQt6, calling self.setCentralWidget(widget) tells the window to assign that widget to occupy the main area. However, if you explicitly set a fixed width and height on that central widget (for example, using main.setFixedWidth(500) and main.setFixedHeight(250)) while the parent window is larger (e.g., 1000x500), PyQt default behavior is to anchor the fixed-size widget to the top-left corner (position 0,0).
Because QMainWindow does not automatically center central widgets that do not expand to fill the available space, relying solely on setCentralWidget() won't position your UI in the middle.
The Solution: Wrap the Widget or Use Layout Alignment
To center a fixed-size container in PyQt6, the recommended approach is to use a outer container widget as the central widget, apply a layout (such as QGridLayout or QVBoxLayout) to it, and center your content widget inside that layout.
Method 1: Use a Wrapper Central Widget (Recommended)
Create a outer dummy QWidget to serve as the actual central widget, set its layout, and add your inner content widget using Qt.AlignmentFlag.AlignCenter.
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QWidget, QGridLayout
# Create the container widget
container = QWidget()
container_layout = QGridLayout(container)
# Create your fixed-size content widget
main = QWidget()
main.setFixedHeight(250)
main.setFixedWidth(500)
main.setLayout(v_layout)
# Add the main content widget to the container with alignment
container_layout.addWidget(main, 0, 0, Qt.AlignmentFlag.AlignCenter)
# Set container as the central widget
self.setCentralWidget(container)Method 2: Remove Fixed Sizes and Use Layout Stretches
Instead of hardcoding fixed sizes like 250x500 on the inner widget, let the PyQt layout system handle sizing dynamically. Adding stretch spaces before and after layout items will center your components cleanly across all display resolutions.
Complete Fixed PyQt6 Code
Here is the updated, working version of your guessing game with proper widget centering:
import sys
import random
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QWidget, QPushButton,
QLabel, QLineEdit, QHBoxLayout, QVBoxLayout, QGridLayout
)
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Guess the number!")
self.setGeometry(100, 100, 1000, 500)
# Create elements
self.number_input = QLineEdit(self)
self.number_input.setFixedHeight(50)
self.submit_btn = QPushButton("Submit", self)
self.submit_btn.setFixedHeight(50)
self.reset_btn = QPushButton("Play Again?", self)
self.reset_btn.setFixedHeight(50)
self.reset_btn.hide()
self.instruct_lbl = QLabel("Enter a number between 1 and 100 inclusive", self)
self.instruct_lbl.setStyleSheet("color: #c1121f; font-size: 20px; font-weight: 700")
self.answer_lbl = QLabel("", self)
self.answer_lbl.setStyleSheet("color: #669bbc; font-size: 20px; font-weight: 700")
# Connect signals
self.submit_btn.clicked.connect(self.submitted)
self.reset_btn.clicked.connect(self.reset)
# Inner layout
h_layout = QHBoxLayout()
v_layout = QVBoxLayout()
h_layout.addWidget(self.number_input, stretch=3)
h_layout.addWidget(self.submit_btn, stretch=1)
h_layout.addWidget(self.reset_btn, stretch=1)
v_layout.addWidget(self.instruct_lbl)
v_layout.addLayout(h_layout)
v_layout.addWidget(self.answer_lbl)
# Content widget with fixed size
main_content = QWidget()
main_content.setLayout(v_layout)
main_content.setFixedSize(500, 250)
# Central container widget to hold and center content
center_container = QWidget()
container_layout = QGridLayout(center_container)
container_layout.addWidget(main_content, 0, 0, Qt.AlignmentFlag.AlignCenter)
self.setCentralWidget(center_container)
# Random answer initialization
self.real_answer = random.randint(1, 100)
def submitted(self):
self.reset_btn.hide()
self.user_answer = self.number_input.text()
self.number_input.clear()
if not self.user_answer.isdigit():
self.answer_lbl.setText("Please enter a valid number!")
return
val = int(self.user_answer)
if val != self.real_answer:
if val > self.real_answer:
self.answer_lbl.setText(f"Incorrect! {val} is more than the answer.")
else:
self.answer_lbl.setText(f"Incorrect! {val} is less than the answer.")
else:
self.answer_lbl.setText(f"Correct! {val} is the answer!")
self.number_input.setEnabled(False)
self.submit_btn.hide()
self.reset_btn.show()
def reset(self):
self.reset_btn.hide()
self.submit_btn.show()
self.real_answer = random.randint(1, 100)
self.answer_lbl.setText("")
self.number_input.setEnabled(True)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec())Summary
Whenever you need a fixed-size widget to sit squarely in the center of a QMainWindow, remember to embed it within an outer container widget utilizing a layout with Qt.AlignmentFlag.AlignCenter.