我们用盖房子来理解 QMainWindow:
QWidget= 毛坯房:四面墙一个顶,什么都没有,所有东西都要自己装QMainWindow= 开发商建好的精装修商品房:自带固定的功能分区(客厅、厨房、阳台),你只需要往里面摆家具就行
一句话核心 :QMainWindow 是 PySide6 专门用来做应用程序主窗口的类,它已经预设好了所有主窗口该有的标准结构,不用你从零搭建。
一、QMainWindow 的 "户型图":固定 5 大功能区
这是 QMainWindow 最关键的知识点 ------ 它有严格固定的布局结构,不能乱改,每个区域都有专属的 API:

⚠️ 最容易踩的坑 :QMainWindow不能直接用 setLayout () 加布局!它有自己内置的布局管理器,所有东西都必须放在上面 5 个区域里。
二、第一步:先 "收房"------ 创建一个空的主窗口
python
import sys
from PySide6.QtWidgets import (QApplication, QMainWindow,
QLabel, QPushButton, QTextEdit)
# 继承QMainWindow,相当于"收房后开始个性化装修"
class MyMainWindow(QMainWindow):
def __init__(self):
super().__init__() # 先调用父类的构造函数,拿到毛坯房
self.init_ui() # 开始装修
def init_ui(self):
# 设置窗口基本属性(相当于给房子挂门牌号、定大小)
self.setWindowTitle("我的第一个主窗口")
self.resize(800, 600) # 宽800,高600
# self.showMaximized() # 直接全屏显示
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyMainWindow()
window.show() # 开门迎客
sys.exit(app.exec())
运行这个代码,你就得到了一个标准的空白主窗口。
三、第二步:装修 "客厅"------ 中心部件 Central Widget
中心部件是 QMainWindow 的灵魂,必须要有! 就像房子不能没有客厅。
- 所有你想展示的核心内容(文本框、按钮、表格、图片)都要放在这里
- 一个主窗口只能有一个中心部件
python
def init_ui(self):
self.setWindowTitle("我的第一个主窗口")
self.resize(800, 600)
# 1. 创建中心部件(相当于买个大沙发放在客厅)
central_widget = QTextEdit() # 用文本编辑器当中心部件
# 2. 把中心部件设置给主窗口
self.setCentralWidget(central_widget)
# 如果你想放多个控件,就先创建一个QWidget,给它加布局,再设为中心部件
# central_widget = QWidget()
# layout = QVBoxLayout(central_widget)
# layout.addWidget(QPushButton("按钮1"))
# layout.addWidget(QLabel("标签1"))
# self.setCentralWidget(central_widget)
四、第三步:装 "总开关"------ 菜单栏 Menu Bar
菜单栏在窗口最顶部,是所有功能的总入口,就像家里玄关的总开关面板。
python
def init_ui(self):
# ... 前面的代码不变
# 1. 获取主窗口自带的菜单栏(不用自己创建)
menu_bar = self.menuBar()
# 2. 添加一级菜单(相当于开关面板上的"灯光"、"空调"分组)
file_menu = menu_bar.addMenu("文件")
edit_menu = menu_bar.addMenu("编辑")
help_menu = menu_bar.addMenu("帮助")
# 3. 给菜单添加动作(相当于分组里的具体开关)
new_action = file_menu.addAction("新建")
open_action = file_menu.addAction("打开")
file_menu.addSeparator() # 添加分隔线
save_action = file_menu.addAction("保存")
file_menu.addSeparator()
exit_action = file_menu.addAction("退出")
# 4. 给动作绑定点击事件(按开关就触发对应的事)
exit_action.triggered.connect(self.close) # 点击退出就关闭窗口
五、第四步:放 "工具抽屉"------ 工具栏 Tool Bar
工具栏在菜单栏下面,放最常用的功能按钮,就像你放在茶几上的遥控器、手机,不用每次都去玄关开总开关。
python
def init_ui(self):
# ... 前面的代码不变
# 1. 创建工具栏
tool_bar = self.addToolBar("常用工具")
# 2. 给工具栏添加动作(可以直接复用菜单栏的动作!)
tool_bar.addAction(new_action)
tool_bar.addAction(open_action)
tool_bar.addAction(save_action)
tool_bar.addSeparator()
# 3. 也可以添加按钮、标签等其他控件
tool_bar.addWidget(QPushButton("一键格式化"))
# 4. 设置工具栏特性
tool_bar.setMovable(True) # 可以拖动(默认True)
tool_bar.setFloatable(True) # 可以悬浮成独立窗口
六、第五步:挂 "留言板"------ 状态栏 Status Bar
状态栏在窗口最底部,用来显示临时提示信息或永久状态,就像门口的留言板。
python
def init_ui(self):
# ... 前面的代码不变
# 1. 获取主窗口自带的状态栏
status_bar = self.statusBar()
# 2. 显示临时消息(5秒后自动消失)
status_bar.showMessage("欢迎使用本程序", 5000)
# 3. 显示永久消息(一直留在右下角)
status_bar.addPermanentWidget(QLabel("版本:v1.0.0"))
七、完整可运行的例子
把上面所有部分拼起来,你就得到了一个有模有样的主窗口:
python
import sys
from PySide6.QtWidgets import (QApplication, QMainWindow,
QLabel, QPushButton, QTextEdit)
class MyMainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("迷你记事本")
self.resize(800, 600)
# 1. 中心部件
self.text_edit = QTextEdit()
self.setCentralWidget(self.text_edit)
# 2. 菜单栏
menu_bar = self.menuBar()
file_menu = menu_bar.addMenu("文件")
new_action = file_menu.addAction("新建")
open_action = file_menu.addAction("打开")
save_action = file_menu.addAction("保存")
file_menu.addSeparator()
exit_action = file_menu.addAction("退出")
exit_action.triggered.connect(self.close)
# 3. 工具栏
tool_bar = self.addToolBar("工具栏")
tool_bar.addAction(new_action)
tool_bar.addAction(open_action)
tool_bar.addAction(save_action)
# 4. 状态栏
self.statusBar().showMessage("就绪", 3000)
self.statusBar().addPermanentWidget(QLabel("迷你记事本 v1.0"))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyMainWindow()
window.show()
sys.exit(app.exec())
八、一句话总结核心
| 部件 | 类比 | 作用 |
|---|---|---|
| QMainWindow | 精装修商品房 | 主窗口容器,自带固定结构 |
| 中心部件 | 客厅 | 放核心内容,必须有且只有一个 |
| 菜单栏 | 玄关总开关 | 所有功能的总入口 |
| 工具栏 | 茶几遥控器 | 放最常用的功能,快速访问 |
| 状态栏 | 门口留言板 | 显示程序状态和提示信息 |
新手黄金法则:做主窗口就用 QMainWindow,不要用 QWidget;所有控件都放在 5 个固定区域里,永远不要给 QMainWindow 直接 setLayout ()。
PySide6 QWidget:用 "毛坯房" 秒懂所有控件的祖宗
延续之前的 "盖房子" 系列,我们用毛坯房来理解 QWidget,这样你就能一眼看清它和 QMainWindow 的本质区别:
QWidget= 纯毛坯房:只有四面墙、一个顶、一个门,什么都没有。水电要自己拉,地板要自己铺,家具要自己买,想怎么装就怎么装QMainWindow= 精装修商品房:开发商已经帮你做好了固定的功能分区(客厅、厨房、阳台),你只需要往里面摆家具就行
一句话核心 :QWidget 是 PySide6 中所有 UI 控件的基类(按钮、标签、文本框、窗口... 全都是 QWidget 的子类)。它是最基础、最灵活、最空白的组件,没有任何预设结构,完全由你自由定制。
一、QWidget 的核心本质
你可以把 QWidget 理解成一个万能的 "容器",它有三重身份:
- 独立窗口:就是我们平时看到的各种弹窗、对话框
- 子容器:用来分组管理其他控件(比如一个面板、一个功能区)
- 基础控件:所有具体控件(QLabel、QPushButton、QTextEdit)本质上都是特殊的 QWidget
⚠️ 最容易踩的坑 :QWidget必须自己设置布局 !否则所有控件都会堆在左上角,窗口缩放时也不会自动调整大小。这和 QMainWindow 正好相反(QMainWindow 不能直接调用setLayout())。
二、第一步:先 "盖好" 一个毛坯房
python
import sys
from PySide6.QtWidgets import QApplication, QWidget
# 继承QWidget,相当于"拿到一块地,开始盖毛坯房"
class MyWindow(QWidget):
def __init__(self):
super().__init__() # 先调用父类的构造函数,打好地基
self.init_ui() # 开始装修
def init_ui(self):
# 设置窗口基本属性(相当于给房子挂门牌号、定大小)
self.setWindowTitle("我的第一个毛坯房窗口")
self.resize(600, 400) # 宽600,高400
# self.setFixedSize(600, 400) # 固定窗口大小,禁止缩放
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyWindow()
window.show() # 开门迎客
sys.exit(app.exec())
运行这个代码,你就得到了一个最纯粹的空白窗口,什么都没有,干干净净。
三、第二步:最重要的一步 ------"装水电铺地板"(设置布局)
这是 QWidget 最核心、最容易出错的地方。毛坯房不能直接摆家具,必须先铺好地板、走好水电,也就是设置布局管理器。
布局管理器就像你给房子画的 "装修平面图",它会自动帮你排列控件,窗口缩放时也会智能调整大小和位置。
PySide6 有 4 种常用布局,对应 4 种不同的排列方式:
| 布局类型 | 装修类比 | 核心作用 |
|---|---|---|
| QHBoxLayout | 横向摆放家具 | 控件水平排成一排 |
| QVBoxLayout | 纵向摆放家具 | 控件垂直排成一列 |
| QGridLayout | 地砖格子 | 控件排成网格状(几行几列) |
| QFormLayout | 填表格式 | 专门用来做 "标签 + 输入框" 的表单 |
我们用最常用的垂直布局来举例:
python
from PySide6.QtWidgets import QVBoxLayout
def init_ui(self):
self.setWindowTitle("我的第一个毛坯房窗口")
self.resize(600, 400)
# 1. 创建布局管理器(相当于画好装修平面图)
# 把布局直接绑定到当前窗口(self)
main_layout = QVBoxLayout(self)
# 2. 设置布局的边距和间距(相当于留好墙距和家具间距)
main_layout.setContentsMargins(30, 30, 30, 30) # 左、上、右、下边距
main_layout.setSpacing(20) # 控件之间的间距
四、第三步:往里面 "摆家具"(添加控件)
布局设置好之后,就可以往里面添加各种控件了,就像往摆好平面图的房子里放沙发、电视、桌子一样。
python
from PySide6.QtWidgets import QLabel, QLineEdit, QPushButton
def init_ui(self):
# ... 前面的代码不变
# 1. 添加标签(相当于在墙上挂一幅画)
# 注意:加self.变成实例属性,这样其他方法也能访问到
self.title_label = QLabel("欢迎来到我的毛坯房")
# 设置标签样式(相当于给画装个好看的框)
self.title_label.setStyleSheet("font-size: 24px; font-weight: bold; color: #2563eb;")
# 把标签添加到布局里
main_layout.addWidget(self.title_label)
# 2. 添加输入框(相当于装一个洗手池)
self.name_input = QLineEdit()
self.name_input.setPlaceholderText("请输入你的名字")
main_layout.addWidget(self.name_input)
# 3. 添加按钮(相当于装一个电灯开关)
hello_button = QPushButton("打个招呼")
main_layout.addWidget(hello_button)
# 4. 添加弹性空间(相当于留一块空地)
# 这样上面的控件会靠上对齐,下面自动留空
main_layout.addStretch()
五、第四步:"安装开关"(连接信号与槽)
家具摆好了,开关也装好了,现在需要把开关和电器连接起来,这样按开关的时候电器才会工作。这就是 PySide6 的灵魂 ------信号与槽机制。
- 信号:控件发出的 "通知"(比如按钮被点击了、输入框内容改变了)
- 槽:接收到信号后要执行的 "动作"(比如弹出提示框、显示一段文字)
python
def init_ui(self):
# ... 前面的代码不变
# 把按钮的"点击"信号,连接到我们自己写的"say_hello"槽函数
hello_button.clicked.connect(self.say_hello)
# 定义槽函数(相当于开关按下后要做的事)
def say_hello(self):
# 获取输入框里的名字
name = self.name_input.text().strip()
if name:
self.title_label.setText(f"你好,{name}!欢迎来到我的毛坯房")
else:
self.title_label.setText("你好,陌生人!请先输入你的名字")
六、完整可运行的例子
把上面所有部分拼起来,你就得到了一个简单但完整的 QWidget 窗口:
python
import sys
from PySide6.QtWidgets import (QApplication, QWidget, QVBoxLayout,
QLabel, QLineEdit, QPushButton)
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("我的第一个毛坯房窗口")
self.resize(600, 400)
# 创建垂直布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(30, 30, 30, 30)
main_layout.setSpacing(20)
# 添加标签
self.title_label = QLabel("欢迎来到我的毛坯房")
self.title_label.setStyleSheet("font-size: 24px; font-weight: bold; color: #2563eb;")
main_layout.addWidget(self.title_label)
# 添加输入框
self.name_input = QLineEdit()
self.name_input.setPlaceholderText("请输入你的名字")
main_layout.addWidget(self.name_input)
# 添加按钮
hello_button = QPushButton("打个招呼")
hello_button.clicked.connect(self.say_hello)
main_layout.addWidget(hello_button)
# 添加弹性空间
main_layout.addStretch()
def say_hello(self):
name = self.name_input.text().strip()
if name:
self.title_label.setText(f"你好,{name}!欢迎来到我的毛坯房")
else:
self.title_label.setText("你好,陌生人!请先输入你的名字")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec())
七、QWidget 的独门绝技:嵌套布局
毛坯房的最大优势就是无限灵活,你可以在一个布局里嵌套另一个布局,就像你可以把房子分成客厅、卧室、厨房一样。
比如,我们想在窗口底部放两个并排的按钮,就可以用一个水平布局嵌套在垂直布局里:
python
from PySide6.QtWidgets import QHBoxLayout
def init_ui(self):
# ... 前面的代码不变
# 创建一个水平布局,专门用来放底部的两个按钮
button_layout = QHBoxLayout()
# 添加两个按钮到水平布局
button_layout.addWidget(QPushButton("确定"))
button_layout.addWidget(QPushButton("取消"))
# 把水平布局添加到主垂直布局的最底部
main_layout.addLayout(button_layout)
八、QWidget vs QMainWindow:一张表搞懂什么时候用哪个
| 特性 | QWidget(毛坯房) | QMainWindow(精装修商品房) |
|---|---|---|
| 预设结构 | 完全空白,什么都没有 | 自带菜单栏、工具栏、状态栏、中心部件、停靠区 |
| 布局方式 | 必须自己调用 setLayout () | 不能直接调用 setLayout (),有内置布局 |
| 灵活性 | 最高,想怎么装就怎么装 | 中等,必须使用固定的 5 个区域 |
| 适用场景 | 弹窗、对话框、子窗口、自定义控件 | 应用程序的主窗口 |
| 学习成本 | 低,简单直接 | 高,有很多专属 API |
九、新手黄金法则
- 主窗口用 QMainWindow,其他所有窗口 / 面板 / 控件都用 QWidget
- 永远先设置布局,再添加控件,绝对不要手动设置控件的 x、y 坐标
- 需要复杂排列时就用嵌套布局,不要试图用一个布局搞定所有事情
- 所有需要在多个方法中访问的控件,都要加 self. 变成实例属性