qt-layouts
4
总安装量
3
周安装量
#52522
全站排名
安装命令
npx skills add https://github.com/l3digital-net/claude-code-plugins --skill qt-layouts
Agent 安装分布
opencode
3
gemini-cli
3
antigravity
3
claude-code
3
github-copilot
3
codex
3
Skill 文档
Qt Layout Managers
Layout Hierarchy
Qt lays out widgets using layout objects attached to containers. Never call setGeometry() manually â use layouts.
QWidget (parent)
âââ QVBoxLayout (attached via setLayout or constructor arg)
âââ QLabel
âââ QHBoxLayout (nested)
â âââ QPushButton
â âââ QPushButton
âââ QTextEdit
Core Layout Types
| Layout | Use case |
|---|---|
QVBoxLayout |
Stack items vertically |
QHBoxLayout |
Stack items horizontally |
QGridLayout |
Row/column grid |
QFormLayout |
Label + field pairs |
QStackedLayout |
Multiple pages, one visible |
Basic Usage
from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QSizePolicy
)
class MyWidget(QWidget):
def __init__(self) -> None:
super().__init__()
# Pass widget as parent to layout â attaches layout automatically
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(12, 12, 12, 12)
main_layout.setSpacing(8)
label = QLabel("Hello")
main_layout.addWidget(label)
# Nested horizontal row
button_row = QHBoxLayout()
button_row.addWidget(QPushButton("OK"))
button_row.addWidget(QPushButton("Cancel"))
main_layout.addLayout(button_row)
Pass the parent widget to the layout constructor (QVBoxLayout(self)) â this is cleaner than calling self.setLayout(layout) separately, and prevents forgetting to attach the layout.
Stretch and Size Policy
Stretch factors distribute extra space when the window resizes:
layout.addWidget(sidebar, stretch=1) # gets 1/4 of extra space
layout.addWidget(main_area, stretch=3) # gets 3/4 of extra space
Size policy controls how individual widgets resize:
# Expand to fill available horizontal space
widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
# Fixed size â never grows or shrinks
widget.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
widget.setFixedSize(200, 40)
Common policies: Fixed, Minimum, Maximum, Preferred, Expanding, MinimumExpanding.
Spacers:
from PySide6.QtWidgets import QSpacerItem, QSizePolicy
# Push buttons to the right
layout.addStretch() # flexible spacer
layout.addSpacing(16) # fixed-size gap
layout.addItem(QSpacerItem( # explicit spacer
40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum
))
QGridLayout
grid = QGridLayout(self)
grid.addWidget(QLabel("Name:"), 0, 0) # row, col
grid.addWidget(name_edit, 0, 1)
grid.addWidget(QLabel("Email:"), 1, 0)
grid.addWidget(email_edit, 1, 1)
grid.addWidget(submit_btn, 2, 0, 1, 2) # row, col, rowspan, colspan
# Column stretch â second column takes all extra space
grid.setColumnStretch(0, 0)
grid.setColumnStretch(1, 1)
QFormLayout
Use for settings dialogs and data entry forms â automatically handles label alignment:
from PySide6.QtWidgets import QFormLayout
form = QFormLayout(self)
form.addRow("Username:", QLineEdit())
form.addRow("Password:", QLineEdit())
form.addRow("", QPushButton("Login")) # empty label for button row
QSplitter
from PySide6.QtWidgets import QSplitter
from PySide6.QtCore import Qt
splitter = QSplitter(Qt.Orientation.Horizontal)
splitter.addWidget(sidebar)
splitter.addWidget(main_content)
splitter.setSizes([200, 600]) # initial pixel widths
splitter.setStretchFactor(0, 0) # sidebar: don't stretch
splitter.setStretchFactor(1, 1) # main: takes all extra space
# Persist splitter state
settings.setValue("splitter", splitter.saveState())
splitter.restoreState(settings.value("splitter"))
Centering a Widget in Its Parent
# Via layout
layout = QVBoxLayout(self)
layout.addStretch()
layout.addWidget(target_widget, alignment=Qt.AlignmentFlag.AlignHCenter)
layout.addStretch()
Debugging Layout Issues
Widget appears but is zero-size:
- Set a size hint:
widget.setMinimumSize(100, 40)or overridesizeHint() - Check that the parent layout is actually attached (
self.layout()returns non-None)
Widget not visible at all:
- Confirm
show()was called (or parent is visible) - Check
isHidden()andisVisible() - Ensure no
setFixedSize(0, 0)or zero margins collapsing the widget
Layout ignoring size changes:
- Call
layout.invalidate()after programmatic geometry changes - Verify size policy is not
Fixedwhen you want expansion
Margins and spacing defaults:
- Default content margins: 9px on all sides (varies by style)
- Reset to zero:
layout.setContentsMargins(0, 0, 0, 0)andlayout.setSpacing(0)