Qt 与 GTK 图形框架教程 / 03 - Qt Widgets 控件 / Qt Widgets
Qt Widgets 控件 / Qt Widgets
全面掌握 Qt Widgets 体系:布局管理、常用控件、对话框、菜单栏和样式定制。 Master Qt Widgets: layouts, controls, dialogs, menus, and styling.
3.1 控件总览 / Widget Overview
核心控件分类 / Core Widget Categories
| 类别 / Category | 控件 / Widgets | 说明 / Description |
|---|---|---|
| 按钮 | QPushButton, QToolButton, QRadioButton, QCheckBox | 各类交互按钮 |
| 输入 | QLineEdit, QTextEdit, QSpinBox, QComboBox | 文本与数值输入 |
| 显示 | QLabel, QProgressBar, QLCDNumber | 信息展示 |
| 容器 | QWidget, QGroupBox, QTabWidget, QStackedWidget | 控件容器 |
| 项视图 | QListView, QTreeView, QTableView | 模型-视图架构 |
| 对话框 | QMessageBox, QFileDialog, QColorDialog | 标准对话框 |
| 主窗口 | QMainWindow, QDockWidget, QStatusBar | 应用主框架 |
继承层次 / Inheritance Hierarchy
QObject
└── QPaintDevice
└── QWidget ← 所有控件的基类
├── QLabel ← 文本/图片标签
├── QPushButton ← 按钮
├── QLineEdit ← 单行文本
├── QTextEdit ← 多行富文本
├── QComboBox ← 下拉列表
├── QSpinBox ← 数值输入
├── QCheckBox ← 复选框
├── QRadioButton ← 单选按钮
├── QSlider ← 滑块
├── QProgressBar ← 进度条
├── QListView ← 列表视图
├── QTreeView ← 树视图
├── QTableView ← 表格视图
├── QGroupBox ← 分组框
├── QTabWidget ← 选项卡容器
└── QMainWindow ← 主窗口
├── QMenuBar ← 菜单栏
├── QToolBar ← 工具栏
└── QStatusBar ← 状态栏
3.2 布局管理 / Layout Management
布局管理器自动处理控件的尺寸和位置,是实现自适应界面的关键。 Layout managers automatically handle widget size and position.
布局类型 / Layout Types
| 布局 / Layout | 类 / Class | 用途 / Purpose |
|---|---|---|
| 水平 | QHBoxLayout | 水平排列 / Horizontal arrangement |
| 垂直 | QVBoxLayout | 垂直排列 / Vertical arrangement |
| 网格 | QGridLayout | 行列网格 / Row-column grid |
| 表单 | QFormLayout | 标签-字段对 / Label-field pairs |
| 堆叠 | QStackedLayout | 一次显示一个 / Show one at a time |
C++ 完整示例 / C++ Complete Example
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QFormLayout>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include <QComboBox>
#include <QSpinBox>
#include <QGroupBox>
#include <QTabWidget>
#include <QSplitter>
#include <QMessageBox>
#include <QFileDialog>
#include <QStatusBar>
#include <QMenuBar>
#include <QToolBar>
#include <QAction>
#include <QApplication>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
private slots:
void onNewFile();
void onAbout();
private:
void createMenus();
void createToolBar();
void createStatusBar();
QWidget *createFormTab();
QWidget *createLayoutTab();
QTextEdit *m_textEdit;
};
#endif // MAINWINDOW_H
// mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle("Qt Widgets 示例 / Qt Widgets Example");
resize(800, 600);
createMenus();
createToolBar();
createStatusBar();
// 主选项卡容器
auto *tabs = new QTabWidget(this);
tabs->addTab(createFormTab(), "表单 / Form");
tabs->addTab(createLayoutTab(), "布局 / Layout");
setCentralWidget(tabs);
}
// ============================================================
// 菜单栏 / Menu Bar
// ============================================================
void MainWindow::createMenus()
{
// 文件菜单 / File Menu
auto *fileMenu = menuBar()->addMenu("文件(&F)");
auto *newAct = new QAction("新建(&N)", this);
newAct->setShortcut(QKeySequence::New);
connect(newAct, &QAction::triggered, this, &MainWindow::onNewFile);
fileMenu->addAction(newAct);
auto *openAct = new QAction("打开(&O)", this);
openAct->setShortcut(QKeySequence::Open);
fileMenu->addAction(openAct);
fileMenu->addSeparator();
auto *exitAct = new QAction("退出(&Q)", this);
exitAct->setShortcut(QKeySequence::Quit);
connect(exitAct, &QAction::triggered, qApp, &QApplication::quit);
fileMenu->addAction(exitAct);
// 编辑菜单 / Edit Menu
auto *editMenu = menuBar()->addMenu("编辑(&E)");
editMenu->addAction("撤销(&U)", QKeySequence::Undo);
editMenu->addAction("重做(&R)", QKeySequence::Redo);
editMenu->addSeparator();
editMenu->addAction("剪切(&T)", QKeySequence::Cut);
editMenu->addAction("复制(&C)", QKeySequence::Copy);
editMenu->addAction("粘贴(&P)", QKeySequence::Paste);
// 帮助菜单 / Help Menu
auto *helpMenu = menuBar()->addMenu("帮助(&H)");
auto *aboutAct = new QAction("关于(&A)", this);
connect(aboutAct, &QAction::triggered, this, &MainWindow::onAbout);
helpMenu->addAction(aboutAct);
}
// ============================================================
// 工具栏 / Tool Bar
// ============================================================
void MainWindow::createToolBar()
{
auto *toolbar = addToolBar("主工具栏 / Main");
toolbar->setMovable(false);
toolbar->addAction("新建", this, &MainWindow::onNewFile);
toolbar->addAction("打开");
toolbar->addAction("保存");
toolbar->addSeparator();
toolbar->addAction("剪切");
toolbar->addAction("复制");
toolbar->addAction("粘贴");
}
// ============================================================
// 状态栏 / Status Bar
// ============================================================
void MainWindow::createStatusBar()
{
statusBar()->showMessage("就绪 / Ready", 3000);
}
// ============================================================
// 表单布局 Tab / Form Layout Tab
// ============================================================
QWidget *MainWindow::createFormTab()
{
auto *widget = new QWidget;
auto *formLayout = new QFormLayout(widget);
formLayout->setLabelAlignment(Qt::AlignRight);
auto *nameEdit = new QLineEdit;
nameEdit->setPlaceholderText("请输入姓名 / Enter name");
formLayout->addRow("姓名 / Name:", nameEdit);
auto *emailEdit = new QLineEdit;
emailEdit->setPlaceholderText("请输入邮箱 / Enter email");
formLayout->addRow("邮箱 / Email:", emailEdit);
auto *ageSpin = new QSpinBox;
ageSpin->setRange(0, 150);
ageSpin->setValue(25);
formLayout->addRow("年龄 / Age:", ageSpin);
auto *countryCombo = new QComboBox;
countryCombo->addItems({"中国 / China", "美国 / USA", "日本 / Japan",
"德国 / Germany", "其他 / Other"});
formLayout->addRow("国家 / Country:", countryCombo);
auto *bioEdit = new QTextEdit;
bioEdit->setPlaceholderText("个人简介 / Bio...");
bioEdit->setMaximumHeight(100);
formLayout->addRow("简介 / Bio:", bioEdit);
// 按钮行 / Button row
auto *btnLayout = new QHBoxLayout;
auto *submitBtn = new QPushButton("提交 / Submit");
auto *resetBtn = new QPushButton("重置 / Reset");
btnLayout->addStretch();
btnLayout->addWidget(submitBtn);
btnLayout->addWidget(resetBtn);
formLayout->addRow("", btnLayout);
return widget;
}
// ============================================================
// 网格布局 Tab / Grid Layout Tab
// ============================================================
QWidget *MainWindow::createLayoutTab()
{
auto *widget = new QWidget;
auto *grid = new QGridLayout(widget);
// 第一行:水平布局 / Row 1: horizontal layout
auto *hGroupBox = new QGroupBox("水平布局 / HBoxLayout");
auto *hLayout = new QHBoxLayout(hGroupBox);
for (int i = 1; i <= 4; ++i) {
hLayout->addWidget(new QPushButton(QString("按钮 %1").arg(i)));
}
grid->addWidget(hGroupBox, 0, 0, 1, 2);
// 第二行左侧:垂直布局 / Row 2 left: vertical layout
auto *vGroupBox = new QGroupBox("垂直布局 / VBoxLayout");
auto *vLayout = new QVBoxLayout(vGroupBox);
for (int i = 1; i <= 3; ++i) {
vLayout->addWidget(new QPushButton(QString("项 %1").arg(i)));
}
vLayout->addStretch();
grid->addWidget(vGroupBox, 1, 0);
// 第二行右侧:分割器 / Row 2 right: splitter
m_textEdit = new QTextEdit;
m_textEdit->setPlainText("这是文本编辑器 / This is a text editor");
auto *rightLabel = new QLabel("右侧面板 / Right Panel");
rightLabel->setAlignment(Qt::AlignCenter);
rightLabel->setStyleSheet("background: #e0e0e0; padding: 20px;");
auto *splitter = new QSplitter(Qt::Vertical);
splitter->addWidget(m_textEdit);
splitter->addWidget(rightLabel);
grid->addWidget(splitter, 1, 1);
return widget;
}
void MainWindow::onNewFile()
{
statusBar()->showMessage("新建文件 / New file created", 3000);
}
void MainWindow::onAbout()
{
QMessageBox::about(this, "关于 / About",
"Qt Widgets 示例程序\nQt Widgets Example\n\nVersion 1.0");
}
Python 完整示例 / Python Complete Example (PySide6)
#!/usr/bin/env python3
"""Qt Widgets 完整示例 - PySide6"""
import sys
from PySide6.QtWidgets import (
QApplication, QMainWindow, QWidget, QTabWidget,
QHBoxLayout, QVBoxLayout, QGridLayout, QFormLayout,
QPushButton, QLabel, QLineEdit, QTextEdit,
QComboBox, QSpinBox, QGroupBox, QSplitter,
QMessageBox, QFileDialog, QStatusBar,
QToolBar
)
from PySide6.QtGui import QAction, QKeySequence
from PySide6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Qt Widgets 示例 / Qt Widgets Example")
self.resize(800, 600)
self._create_menus()
self._create_toolbar()
self._create_statusbar()
tabs = QTabWidget()
tabs.addTab(self._create_form_tab(), "表单 / Form")
tabs.addTab(self._create_layout_tab(), "布局 / Layout")
self.setCentralWidget(tabs)
def _create_menus(self):
# 文件菜单
file_menu = self.menuBar().addMenu("文件(&F)")
new_act = QAction("新建(&N)", self)
new_act.setShortcut(QKeySequence.StandardKey.New)
new_act.triggered.connect(self._on_new_file)
file_menu.addAction(new_act)
file_menu.addSeparator()
exit_act = QAction("退出(&Q)", self)
exit_act.setShortcut(QKeySequence.StandardKey.Quit)
exit_act.triggered.connect(QApplication.quit)
file_menu.addAction(exit_act)
# 帮助菜单
help_menu = self.menuBar().addMenu("帮助(&H)")
about_act = QAction("关于(&A)", self)
about_act.triggered.connect(self._on_about)
help_menu.addAction(about_act)
def _create_toolbar(self):
toolbar = self.addToolBar("主工具栏")
toolbar.setMovable(False)
toolbar.addAction("新建", self._on_new_file)
toolbar.addAction("打开")
toolbar.addAction("保存")
def _create_statusbar(self):
self.statusBar().showMessage("就绪 / Ready", 3000)
def _create_form_tab(self) -> QWidget:
widget = QWidget()
form = QFormLayout(widget)
form.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
name_edit = QLineEdit()
name_edit.setPlaceholderText("请输入姓名")
form.addRow("姓名 / Name:", name_edit)
email_edit = QLineEdit()
email_edit.setPlaceholderText("请输入邮箱")
form.addRow("邮箱 / Email:", email_edit)
age_spin = QSpinBox()
age_spin.setRange(0, 150)
age_spin.setValue(25)
form.addRow("年龄 / Age:", age_spin)
country = QComboBox()
country.addItems(["中国", "美国", "日本", "德国", "其他"])
form.addRow("国家 / Country:", country)
bio = QTextEdit()
bio.setPlaceholderText("个人简介...")
bio.setMaximumHeight(100)
form.addRow("简介 / Bio:", bio)
btn_layout = QHBoxLayout()
btn_layout.addStretch()
btn_layout.addWidget(QPushButton("提交 / Submit"))
btn_layout.addWidget(QPushButton("重置 / Reset"))
form.addRow("", btn_layout)
return widget
def _create_layout_tab(self) -> QWidget:
widget = QWidget()
grid = QGridLayout(widget)
# 水平布局
h_group = QGroupBox("水平布局 / HBoxLayout")
h_layout = QHBoxLayout(h_group)
for i in range(1, 5):
h_layout.addWidget(QPushButton(f"按钮 {i}"))
grid.addWidget(h_group, 0, 0, 1, 2)
# 垂直布局
v_group = QGroupBox("垂直布局 / VBoxLayout")
v_layout = QVBoxLayout(v_group)
for i in range(1, 4):
v_layout.addWidget(QPushButton(f"项 {i}"))
v_layout.addStretch()
grid.addWidget(v_group, 1, 0)
# 分割器
text_edit = QTextEdit()
text_edit.setPlainText("文本编辑器 / Text Editor")
label = QLabel("右侧面板 / Right Panel")
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setStyleSheet("background: #e0e0e0; padding: 20px;")
splitter = QSplitter(Qt.Orientation.Vertical)
splitter.addWidget(text_edit)
splitter.addWidget(label)
grid.addWidget(splitter, 1, 1)
return widget
def _on_new_file(self):
self.statusBar().showMessage("新建文件 / New file", 3000)
def _on_about(self):
QMessageBox.about(self, "关于 / About",
"Qt Widgets 示例程序\nVersion 1.0")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
3.3 布局伸缩因子 / Layout Stretch Factors
伸缩因子控制控件在窗口缩放时的相对比例。 Stretch factors control the relative ratio when the window resizes.
// 伸缩因子示例 / Stretch factor example
auto *layout = new QHBoxLayout;
// 左侧占 1 份,右侧占 3 份(窗口缩放时右侧是左侧的 3 倍宽)
auto *leftPanel = new QWidget;
auto *rightPanel = new QWidget;
layout->addWidget(leftPanel, 1); // stretch = 1
layout->addWidget(rightPanel, 3); // stretch = 3
布局尺寸策略 / Size Policy
| 策略 / Policy | 说明 / Description |
|---|---|
Fixed | 固定大小,不拉伸 / Fixed size, no stretch |
Minimum | 最小尺寸,可拉伸 / Minimum size, can stretch |
Maximum | 最大尺寸,可压缩 / Maximum size, can shrink |
Preferred | 首选尺寸,可拉伸压缩 / Preferred, flexible |
Expanding | 尽量占据更多空间 / Expands as much as possible |
MinimumExpanding | 最小尺寸,但尽量扩展 / Min size, tries to expand |
auto *btn = new QPushButton("固定宽度");
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
btn->setFixedWidth(120);
3.4 常用对话框 / Standard Dialogs
对话框速查表 / Dialog Quick Reference
| 对话框 / Dialog | 类 / Class | 用途 / Purpose |
|---|---|---|
| 信息框 | QMessageBox::information() | 提示信息 / Info message |
| 警告框 | QMessageBox::warning() | 警告信息 / Warning |
| 错误框 | QMessageBox::critical() | 错误信息 / Critical error |
| 确认框 | QMessageBox::question() | 确认操作 / Confirmation |
| 文件选择 | QFileDialog::getOpenFileName() | 打开文件 / Open file |
| 保存文件 | QFileDialog::getSaveFileName() | 保存文件 / Save file |
| 选择目录 | QFileDialog::getExistingDirectory() | 选目录 / Select dir |
| 颜色选择 | QColorDialog::getColor() | 选颜色 / Pick color |
| 字体选择 | QFontDialog::getFont() | 选字体 / Pick font |
| 输入文本 | QInputDialog::getText() | 文本输入 / Text input |
C++ 示例 / C++ Example
#include <QMessageBox>
#include <QFileDialog>
#include <QColorDialog>
#include <QFontDialog>
#include <QInputDialog>
void dialogExamples(QWidget *parent)
{
// 信息框
QMessageBox::information(parent, "提示 / Info",
"操作成功完成\nOperation completed.");
// 确认框
auto reply = QMessageBox::question(parent, "确认 / Confirm",
"确定要删除吗?\nAre you sure to delete?",
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
// 执行删除
}
// 文件选择
QString file = QFileDialog::getOpenFileName(parent,
"打开文件 / Open File",
QDir::homePath(),
"文本文件 (*.txt);;所有文件 (*.*)");
// 颜色选择
QColor color = QColorDialog::getColor(Qt::white, parent,
"选择颜色 / Pick Color");
if (color.isValid()) {
qDebug() << "Selected color:" << color.name();
}
// 字体选择
bool ok;
QFont font = QFontDialog::getFont(&ok, QFont("Arial", 12), parent);
if (ok) {
qDebug() << "Selected font:" << font.family();
}
// 输入对话框
QString text = QInputDialog::getText(parent,
"输入 / Input", "请输入名称 / Enter name:",
QLineEdit::Normal, "", &ok);
if (ok && !text.isEmpty()) {
qDebug() << "User entered:" << text;
}
}
Python 示例 / Python Example
from PySide6.QtWidgets import (
QMessageBox, QFileDialog, QColorDialog,
QFontDialog, QInputDialog
)
from PySide6.QtGui import QColor, QFont
def dialog_examples(parent):
"""常用对话框示例"""
# 信息框
QMessageBox.information(parent, "提示", "操作成功")
# 确认框
reply = QMessageBox.question(parent, "确认", "确定要删除吗?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
print("User confirmed deletion")
# 文件选择
file, _ = QFileDialog.getOpenFileName(
parent, "打开文件", "", "文本文件 (*.txt);;所有文件 (*)")
# 颜色选择
color = QColorDialog.getColor(QColor("white"), parent, "选择颜色")
if color.isValid():
print(f"Selected: {color.name()}")
# 输入对话框
text, ok = QInputDialog.getText(parent, "输入", "请输入名称:")
if ok and text:
print(f"Entered: {text}")
3.5 样式与 QSS / Styling with QSS
Qt 样式表(QSS)语法类似 CSS,用于定制控件外观。 Qt Style Sheets (QSS) syntax is similar to CSS for customizing widget appearance.
常用 QSS 选择器 / Common QSS Selectors
| 选择器 / Selector | 示例 / Example | 说明 / Description |
|---|---|---|
| 类型选择器 | QPushButton { } | 所有 QPushButton / All QPushButtons |
| 类选择器 | .QPushButton { } | 精确类型 / Exact type only |
| ID 选择器 | #myButton { } | objectName 匹配 / By objectName |
| 属性选择器 | QPushButton[flat="true"] { } | 属性匹配 / By property |
| 后代选择器 | QGroupBox QPushButton { } | 后代控件 / Descendant widgets |
| 子选择器 | QGroupBox > QPushButton { } | 直接子控件 / Direct children |
| 伪状态 | QPushButton:hover { } | 鼠标悬停 / Mouse hover |
完整样式示例 / Complete Style Example
// appstyle.h
#ifndef APPSTYLE_H
#define APPSTYLE_H
#include <QString>
inline QString applicationStyle() {
return R"(
/* 主窗口 / Main Window */
QMainWindow {
background-color: #f5f5f5;
}
/* 菜单栏 / Menu Bar */
QMenuBar {
background-color: #2c3e50;
color: #ecf0f1;
padding: 2px;
}
QMenuBar::item:selected {
background-color: #3498db;
border-radius: 4px;
}
QMenu {
background-color: #2c3e50;
color: #ecf0f1;
border: 1px solid #34495e;
}
QMenu::item:selected {
background-color: #3498db;
}
/* 按钮 / Buttons */
QPushButton {
background-color: #3498db;
color: white;
border: none;
border-radius: 4px;
padding: 8px 16px;
font-weight: bold;
}
QPushButton:hover {
background-color: #2980b9;
}
QPushButton:pressed {
background-color: #21618c;
}
QPushButton:disabled {
background-color: #bdc3c7;
color: #7f8c8d;
}
/* 危险按钮 / Danger Button */
QPushButton[cssClass="danger"] {
background-color: #e74c3c;
}
QPushButton[cssClass="danger"]:hover {
background-color: #c0392b;
}
/* 输入框 / Input Fields */
QLineEdit, QTextEdit, QSpinBox, QComboBox {
background-color: white;
border: 2px solid #dcdde1;
border-radius: 4px;
padding: 6px;
color: #2c3e50;
}
QLineEdit:focus, QTextEdit:focus {
border-color: #3498db;
}
/* 选项卡 / Tabs */
QTabWidget::pane {
border: 1px solid #dcdde1;
border-radius: 4px;
background: white;
}
QTabBar::tab {
background: #dcdde1;
padding: 8px 16px;
margin-right: 2px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
QTabBar::tab:selected {
background: white;
font-weight: bold;
}
/* 分组框 / Group Box */
QGroupBox {
font-weight: bold;
border: 1px solid #dcdde1;
border-radius: 4px;
margin-top: 8px;
padding-top: 16px;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 10px;
padding: 0 6px;
}
/* 状态栏 / Status Bar */
QStatusBar {
background-color: #2c3e50;
color: #ecf0f1;
}
/* 滚动条 / Scrollbar */
QScrollBar:vertical {
background: #f5f5f5;
width: 10px;
border-radius: 5px;
}
QScrollBar::handle:vertical {
background: #bdc3c7;
border-radius: 5px;
min-height: 30px;
}
QScrollBar::handle:vertical:hover {
background: #95a5a6;
}
)";
}
#endif // APPSTYLE_H
// main.cpp - 应用样式
#include <QApplication>
#include "mainwindow.h"
#include "appstyle.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setStyleSheet(applicationStyle());
MainWindow window;
window.show();
return app.exec();
}
3.6 QMessageBox 按钮定制 / Custom QMessageBox
// 自定义消息框 / Custom message box
QMessageBox msgBox;
msgBox.setWindowTitle("保存更改 / Save Changes");
msgBox.setText("文档已修改。是否保存?\nDocument modified. Save?");
msgBox.setInformativeText("您的更改将丢失,如果不保存。\n"
"Changes will be lost if not saved.");
msgBox.setStandardButtons(QMessageBox::Save
| QMessageBox::Discard
| QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
msgBox.setIcon(QMessageBox::Warning);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Save:
// 保存
break;
case QMessageBox::Discard:
// 丢弃
break;
case QMessageBox::Cancel:
// 取消
break;
}
注意事项 / Important Notes
⚠️ 不要手动设置几何属性 / Don’t Set Geometry Manually
使用布局管理器而非
setGeometry()。手动设置的控件在窗口缩放时不会自适应。 Use layouts instead ofsetGeometry(). Manual geometry won’t adapt on resize.
⚠️ QSS 性能 / QSS Performance
大量使用复杂 QSS 选择器可能影响性能。优先使用 ID 选择器
#name。 Heavy QSS selectors may impact performance. Prefer ID selectors#name.
⚠️ 内存管理 / Memory Management
传入父对象的控件会自动释放。
new时务必指定parent或手动delete。 Widgets with parents are auto-deleted. Always passparentor manuallydelete.
⚠️ 对话框阻塞 / Dialog Blocking
QMessageBox::exec()和QFileDialog::getOpenFileName()是阻塞调用。 非模态对话框使用show()代替exec()。
exec()calls are blocking. Useshow()for non-modal dialogs.
业务场景 / Business Scenarios
| 场景 / Scenario | 推荐控件 / Recommended |
|---|---|
| 设置面板 | QFormLayout + QGroupBox + QTabWidget |
| 数据录入表单 | QFormLayout + QSpinBox + QComboBox |
| 文本编辑器 | QTextEdit + QMenuBar + QToolBar + QStatusBar |
| 文件管理器 | QTreeView + QListView + QSplitter |
| 仪表盘 | QGridLayout + 自定义 QWidget + QChart |
| 属性编辑器 | QTreeView + QStyledItemDelegate |
扩展阅读 / Further Reading
| 资源 / Resource | 链接 / Link |
|---|---|
| Qt Widgets 文档 | https://doc.qt.io/qt-6/widget-classes.html |
| 布局管理 | https://doc.qt.io/qt-6/layout.html |
| QSS 参考 | https://doc.qt.io/qt-6/stylesheet-reference.html |
| Qt Designer 教程 | https://doc.qt.io/qt-6/designer-using-a-ui-file.html |