QT常用控件使用大全
Qt 常用控件使用大全(含常见问题与实战示例)
本文旨在为 Qt 开发者提供一份全栈式控件使用参考:从基础控件入门、复杂容器组合,到模型/视图框架与常见疑难排查。示例默认使用 Qt 6 + C++,并补充 PySide6/PyQt6 对应写法(若有差异将特别指出)。
目录总览
- 快速上手与工程建议
- 信号与槽速查表
- 基础展示类控件
- 交互按钮与动作控件
- 文本与数据输入控件
- 选择、切换与进度控件
- 列表、树与表格控件
- 容器、布局与导航控件
- 菜单、工具栏与命令体系
- 常用对话框与文件/颜色选择
- 模型-视图(Model/View)模式速览
- 常见问题与解决方案
- 性能调优与调试技巧
- 附录:推荐资源与进阶阅读
快速上手与工程建议
-
创建 Qt 项目:推荐使用 CMake(Qt 6 默认),示例最小模板:
cmake_minimum_required(VERSION 3.16) project(QtControlsDemo LANGUAGES CXX)set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON)find_package(Qt6 REQUIRED COMPONENTS Widgets)add_executable(QtControlsDemomain.cppresources.qrc )target_link_libraries(QtControlsDemo PRIVATE Qt6::Widgets)
-
推荐目录结构:
src/main.cppviews/ # 界面类,如 MainWindow、Dialogswidgets/ # 自定义控件models/ # 自定义数据模型controllers/ # 业务逻辑或 presenter resources/qml/ # 若混合 QMLimages/styles/
-
最佳实践:
- 将 UI 构造逻辑与业务逻辑分离,便于维护与测试。
- 善用 Qt Designer 生成
.ui
文件(通过QUiLoader
或uic
转换)。 - 使用
QObject::connect
的新语法(函数指针或&Class::signal
),避免旧式宏。 - 统一资源管理:使用 Qt Resource (
.qrc
) 将图片、样式、翻译文件打包。 - 对于 PySide6/PyQt6,使用虚拟环境并
pip install PySide6
或pip install PyQt6
,示例差异会在代码中注释。
信号与槽速查表
操作场景 | 常用信号 | 常用槽/处理方式 |
---|---|---|
按钮点击 | QPushButton::clicked(bool) | 自定义槽函数、lambda |
文本输入变更 | QLineEdit::textChanged(const QString&) | 校验输入、启用/禁用按钮 |
复选框状态变更 | QCheckBox::stateChanged(int) | 根据 Qt::CheckState 更新 UI |
列表项选择 | QListWidget::currentRowChanged(int) | 切换 QStackedWidget 页(示例详见常见问题) |
模型数据更新 | QAbstractItemModel::dataChanged | 视图自动刷新 |
进度条更新 | QProgressBar::setValue(int) | 更新界面显示或触发下一步骤 |
异步任务完成(自定义) | QThread::finished() 、自定义信号 | 停止线程、启用 UI 控件 |
📌 提示:使用
QObject::connect(sender, &Sender::signal, receiver, [this](){ ... });
可直接捕获 lambda,实现就地处理逻辑。
基础展示类控件
1. QWidget
/ QMainWindow
-
用途:所有控件的基类;
QMainWindow
提供菜单栏、工具栏、状态栏标准框架。 -
核心 API:
setWindowTitle(const QString&)
resize(int, int)
/setFixedSize
setCentralWidget(QWidget*)
(仅QMainWindow
)
-
示例:
int main(int argc, char *argv[]) {QApplication app(argc, argv);QMainWindow window;window.setWindowTitle("Qt 控件大全演示");auto central = new QWidget(&window);auto layout = new QVBoxLayout(central);layout->addWidget(new QLabel("欢迎使用 Qt!"));window.setCentralWidget(central);window.resize(640, 480);window.show();return app.exec(); }
-
常见问题:
- 窗口不显示:确认调用了
show()
;若在栈上创建QWidget
,生命周期是否正确。 - 中文乱码:确保使用 UTF-8 编码并在
main()
中调用QTextCodec
(Qt5)或设置适当字体(Qt6 默认 UTF-8)。
- 窗口不显示:确认调用了
2. QLabel
-
用途:显示文本、图片或富文本。
-
亮点功能:
setTextFormat(Qt::RichText)
支持 HTML。setPixmap(const QPixmap&)
显示图片。setWordWrap(true)
自动换行。
-
示例:
auto label = new QLabel("<b>状态:</b> <span style='color:#2563eb;'>就绪</span>"); label->setTextFormat(Qt::RichText); label->setAlignment(Qt::AlignCenter);
-
PySide6:
label = QLabel("欢迎 <i>Qt</i>") label.setAlignment(Qt.AlignCenter)
-
常见问题:
- 图片不显示:确认资源路径正确,或使用
QResource
。 - 需要交互(如超链接):启用
setOpenExternalLinks(true)
,并使用 HTML<a href>
。
- 图片不显示:确认资源路径正确,或使用
交互按钮与动作控件
1. QPushButton
-
用途:最常见按钮,可设置文本、图标,支持默认按钮、可选中状态。
-
关键属性:
setDefault(true)
:回车触发。setCheckable(true)
:切换按钮。setIcon(QIcon("/path/icon.svg"))
:图标按钮。
-
示例:
auto button = new QPushButton(tr("提交")); button->setDefault(true); connect(button, &QPushButton::clicked, this, &MainWindow::onSubmitClicked);
-
常见问题:
- 禁用但仍可触发快捷键:需要额外禁用
QAction
或逻辑判断。 - 图标偏移:检查
setIconSize
与setStyleSheet
是否影响内边距。
- 禁用但仍可触发快捷键:需要额外禁用
2. QToolButton
-
特性:
- 常用于工具栏,支持
MenuButtonPopup
,展开菜单。 - 可设置
toolButtonStyle
控制图文排列。
- 常用于工具栏,支持
-
示例(含菜单):
auto toolBtn = new QToolButton; toolBtn->setText("导出"); toolBtn->setIcon(QIcon(":/icons/export.svg")); toolBtn->setPopupMode(QToolButton::MenuButtonPopup);auto menu = new QMenu(toolBtn); menu->addAction("导出为 PDF", this, &MainWindow::exportPdf); menu->addAction("导出为 CSV", this, &MainWindow::exportCsv); toolBtn->setMenu(menu);
3. QAction
-
用途:抽象操作,可同时附着到菜单、工具栏、快捷键。
-
关键 API:
setShortcut(QKeySequence("Ctrl+S"))
setIcon
triggered(bool)
信号
-
示例:
auto saveAction = new QAction(tr("保存"), this); saveAction->setShortcut(QKeySequence::Save); connect(saveAction, &QAction::triggered, this, &MainWindow::save);menuBar()->addAction(saveAction); toolBar->addAction(saveAction);
文本与数据输入控件
1. QLineEdit
-
用途:单行文本输入,支持验证器、占位符、清除按钮。
-
常用特性:
setPlaceholderText("请输入用户名")
setEchoMode(QLineEdit::Password)
setClearButtonEnabled(true)
-
输入校验:
- 数值:
lineEdit->setValidator(new QIntValidator(0, 100, lineEdit));
- 正则:
QRegularExpressionValidator
- 数值:
-
示例:
auto email = new QLineEdit; email->setPlaceholderText("user@example.com"); email->setValidator(new QRegularExpressionValidator(QRegularExpression(R"(^[\w.-]+@[\w.-]+\.\w+$)") , email));
2. QTextEdit
& QPlainTextEdit
-
QTextEdit
:富文本编辑,支持 HTML、Markdown。 -
QPlainTextEdit
:纯文本,大文本性能更好。 -
常见用法:
- 加载 Markdown:
textEdit->setMarkdown(content);
- 代码行号:结合
QPlainTextEdit
+ 自定义行号边栏。
- 加载 Markdown:
-
保存/加载文件:
QFile file(path); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {textEdit->setPlainText(QString::fromUtf8(file.readAll())); }
3. 数值输入族:QSpinBox
/ QDoubleSpinBox
-
用途:整数/浮点输入带增减按钮。
-
关键设置:
setRange(min, max)
setSingleStep(step)
setSuffix(" cm")
/setPrefix("¥")
-
示例:
auto price = new QDoubleSpinBox; price->setRange(0.0, 9999.99); price->setDecimals(2); price->setPrefix("¥");
4. QComboBox
- 用途:下拉选择,支持可编辑模式及绑定模型。
- 数据填充:
- 静态添加:
combo->addItem("北京", QVariant(110000));
- 绑定模型:
combo->setModel(cityModel);
- 静态添加:
- 可编辑模式:
combo->setEditable(true); combo->completer()->setCompletionMode(QCompleter::PopupCompletion);
- 信号:
currentIndexChanged(int)
、currentTextChanged(const QString&)
5. 日期与时间:QDateEdit
、QTimeEdit
、QDateTimeEdit
- 设置默认值:
dateEdit->setDate(QDate::currentDate());
- 自定义显示格式:
setDisplayFormat("yyyy-MM-dd");
- 启用日历弹窗:
setCalendarPopup(true);
6. 自动完成:QCompleter
-
用途:为
QLineEdit
、QComboBox
等输入控件提供自动补全。 -
基本用法:
QStringList suggestions{"Qt", "Qt Quick", "Qt Creator", "Qt Design Studio"}; auto completer = new QCompleter(suggestions, this); completer->setCaseSensitivity(Qt::CaseInsensitive); completer->setFilterMode(Qt::MatchContains); // 支持子串匹配 auto lineEdit = new QLineEdit; lineEdit->setCompleter(completer);
-
高级技巧:
- 将
QCompleter
与QAbstractItemModel
(如数据库查询结果)结合,实现动态补全。 - 使用
setWrapAround(true)
支持循环选择。 - 在中文输入法环境下,如果想等候 IME 确认,可监听
QLineEdit::inputMethodEvent
。
- 将
选择、切换与进度控件
1. QCheckBox
& QRadioButton
-
CheckBox:多选;
setTristate(true)
支持部分选中(Qt::PartiallyChecked
)。 -
RadioButton:互斥组搭配
QButtonGroup
。 -
示例:
auto themeGroup = new QButtonGroup(this); themeGroup->addButton(new QRadioButton("浅色"), 0); themeGroup->addButton(new QRadioButton("深色"), 1); connect(themeGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),this, &MainWindow::applyTheme);
2. QSlider
& QDial
- 用途:连续值调节。
- 关键点:
setOrientation(Qt::Horizontal)
setTickPosition(QSlider::TicksBelow)
- 结合
valueChanged(int)
更新标签或模型。
3. QProgressBar
-
用途:展示任务进度,支持不确定模式(
setRange(0, 0)
)。 -
示例:
progressBar->setRange(0, 100); progressBar->setValue(loadingProgress); progressBar->setFormat("加载中 %p%" );
4. QProgressDialog
- 用途:长任务反馈,可带取消按钮。
- 关键:设定
setMinimumDuration
避免闪烁;连接canceled()
槽中断任务。
5. QCalendarWidget
-
用途:提供可视化日历选择,常用于预订、排期等场景。
-
关键点:
- 使用
setGridVisible(true)
展示网格。 - 结合
setMinimumDate
/setMaximumDate
限制日期范围。 - 通过
selectionChanged()
信号捕获用户选择。
- 使用
-
日期高亮:可重写
QCalendarWidget::paintCell
或使用setDateTextFormat
为特定日期设置颜色与字体。 -
示例:
auto calendar = new QCalendarWidget; calendar->setFirstDayOfWeek(Qt::Monday); calendar->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader); QObject::connect(calendar, &QCalendarWidget::selectionChanged, calendar, [calendar]{qDebug() << "选中日期" << calendar->selectedDate(); });
列表、树与表格控件
本节涵盖基于
QListWidget
等 Item-based 控件与基于 Model/View 的控件。实际项目推荐使用 Model/View 获取更高可扩展性。
1. QListWidget
-
用途:简单列表,内部自建
QListWidgetItem
。 -
常用 API:
addItem(QString)
、item(int)
、takeItem(int)
。 -
自定义项:
auto item = new QListWidgetItem(QIcon(":/icons/user.svg"), "管理员"); item->setData(Qt::UserRole, QVariant::fromValue(userId)); listWidget->addItem(item);
-
信号:
currentRowChanged(int)
、itemClicked(QListWidgetItem*)
。
2. QTableWidget
-
用途:简单二维表格,基于
QTableWidgetItem
。 -
示例:
auto table = new QTableWidget(3, 2); table->setHorizontalHeaderLabels({"姓名", "部门"}); table->setItem(0, 0, new QTableWidgetItem("张三")); table->setItem(0, 1, new QTableWidgetItem("研发"));
-
合并单元格:
table->setSpan(0, 0, 2, 1);
3. QTreeWidget
-
用途:层级结构,如目录树。
-
示例:
auto root = new QTreeWidgetItem(treeWidget, {"项目"}); new QTreeWidgetItem(root, {"文档"}); new QTreeWidgetItem(root, {"源代码"}); treeWidget->expandAll();
4. Model/View 版控件(详见第 11 章)
QListView
、QTableView
、QTreeView
需配合QAbstractItemModel
。- 提供更高性能、排序过滤、数据共享等。
5. QTableView
+ 自定义模型示例
-
使用场景:当需要展示数据库或复杂结构化数据(如多列表头、动态更新)时,推荐使用视图 + 模型。
-
模型示例:继承
QAbstractTableModel
并实现核心接口:class PeopleModel : public QAbstractTableModel {Q_OBJECT public:explicit PeopleModel(QObject* parent = nullptr): QAbstractTableModel(parent) {}struct Person { QString name; QString department; int age; };void setDataSet(QVector<Person> list) {beginResetModel();people = std::move(list);endResetModel();}int rowCount(const QModelIndex& parent) const override {return parent.isValid() ? 0 : people.size();}int columnCount(const QModelIndex& parent) const override {return parent.isValid() ? 0 : 3;}QVariant data(const QModelIndex& index, int role) const override {if (!index.isValid() || index.row() >= people.size()) return {};const auto& person = people.at(index.row());if (role == Qt::DisplayRole) {switch (index.column()) {case 0: return person.name;case 1: return person.department;case 2: return person.age;}}return {};}QVariant headerData(int section, Qt::Orientation orientation, int role) const override {if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {static const QStringList headers{"姓名", "部门", "年龄"};return headers.value(section);}return QAbstractTableModel::headerData(section, orientation, role);}private:QVector<Person> people; };
-
绑定视图:
auto model = new PeopleModel(this); model->setDataSet({{"陈珊", "研发", 28}, {"李雷", "设计", 25}}); auto view = new QTableView; view->setModel(model); view->setSelectionBehavior(QAbstractItemView::SelectRows); view->setAlternatingRowColors(true); view->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
-
扩展:
- 使用
QSortFilterProxyModel
实现动态筛选。 - 重写
flags()
返回Qt::ItemIsEditable
支持双击编辑。 - 提供自定义委托(见第 11 章)实现下拉框、进度条等复杂单元格。
- 使用
容器、布局与导航控件
1. 布局管理基础
-
常用布局:
QHBoxLayout
、QVBoxLayout
、QGridLayout
、QFormLayout
。 -
设置伸缩因子:
layout->setStretch(index, factor);
-
在窗口中使用:
auto layout = new QGridLayout; layout->addWidget(userLabel, 0, 0); layout->addWidget(userLineEdit, 0, 1); layout->addWidget(passwordLabel, 1, 0); layout->addWidget(passwordLineEdit, 1, 1); centralWidget->setLayout(layout);
2. QGroupBox
- 用途:分组控件,可选标题与可选中状态(
setCheckable(true)
)。 - 示例:用于启用/禁用高级设置。
3. QTabWidget
- 用途:分页导航。
- API:
addTab(QWidget*, const QString&)
setTabsClosable(true)
+ 连接tabCloseRequested
。
- 自定义标签:使用
tabBar()->setTabButton()
。
4. QStackedWidget
- 用途:多页切换,常与
QListWidget
、按钮组搭配。 - 关键:
setCurrentIndex(int)
、setCurrentWidget(QWidget*)
。 - 示例:详见常见问题章节(列表控制页面切换)。
5. QSplitter
-
用途:可拖拽分割区域,常用于 IDE 布局。
-
示例:
auto splitter = new QSplitter(Qt::Horizontal); splitter->addWidget(projectTree); splitter->addWidget(editorStack); splitter->setStretchFactor(1, 2);
6. QScrollArea
- 用途:可滚动区域,适合内容超出时使用。
- 注意:内容控件需设置适当的最小尺寸或使用布局填充。
7. QDockWidget
与 QMdiArea
-
QDockWidget
:- 适合 IDE、管理后台等需要停靠面板的场景。
- 典型用法:在
QMainWindow
中使用addDockWidget(Qt::LeftDockWidgetArea, dockWidget)
。 - 支持浮动、隐藏与
visibilityChanged(bool)
信号。 - 可与
QSettings
搭配保存停靠布局:saveState()
/restoreState()
。
-
QMdiArea
:- 提供多文档界面(MDI),可平铺与层叠子窗口。
- 常用 API:
addSubWindow(QWidget*)
、setViewMode(QMdiArea::TabbedView)
。 - 若需要无边框子窗口,可设置
subWindow->setWindowFlags(Qt::FramelessWindowHint)
。
-
组合实例:
auto mdi = new QMdiArea; mdi->setViewMode(QMdiArea::TabbedView); mdi->setTabsMovable(true);auto dock = new QDockWidget("项目浏览", this); dock->setWidget(projectTree); addDockWidget(Qt::LeftDockWidgetArea, dock); setCentralWidget(mdi); mdi->addSubWindow(new QTextEdit("README"));
-
常见问题:
- DockWidget 在还原布局时尺寸异常:确保
restoreState()
调用在所有 dock 初始化完成之后。 - MDI 子窗口关闭信号:连接
QMdiSubWindow::aboutToActivate
、destroyed(QObject*)
管理状态。
- DockWidget 在还原布局时尺寸异常:确保
菜单、工具栏与命令体系
-
QMenuBar
:menuBar()->addMenu("文件")
。 -
QMenu
:支持子菜单、复选项、单选项。 -
QToolBar
:addToolBar(Qt::TopToolBarArea, toolBar);
-
快捷键:
QAction::setShortcut(QKeySequence("Ctrl+N"))
。 -
上下文菜单:
listWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(listWidget, &QWidget::customContextMenuRequested,this, &MainWindow::showListContextMenu);
常用对话框与文件/颜色选择
对话框 | 静态方法示例 | 注意事项 |
---|---|---|
QFileDialog | QFileDialog::getOpenFileName(this, "选择文件") | 可设置过滤器 "Images (*.png)" |
QColorDialog | QColorDialog::getColor(Qt::white, this) | 检查返回值 isValid() |
QFontDialog | QFontDialog::getFont(&ok, this) | 需捕获 ok |
QInputDialog | QInputDialog::getText(this, "输入", "名称") | 支持 int/double 构造 |
QMessageBox | QMessageBox::information(this, "提示", "已完成") | 也可使用 setStandardButtons |
- 自定义对话框:继承
QDialog
,在构造函数中布置布局和控件,使用exec()
模态显示。 - 异步对话框:对于长时间操作,可使用
open()
+ 信号槽而非exec()
,避免阻塞主线程。 - 常用技巧:
- 使用
QFileDialog::setFileMode(QFileDialog::ExistingFiles)
支持多选。 - 通过
setOption(QFileDialog::DontUseNativeDialog)
获得统一外观并能自定义列。 QColorDialog
在深色模式下显示异常,可调用dialog->setOption(QColorDialog::DontUseNativeDialog)
。- 对话框父对象传入
this
可以确保置顶并随主窗口一起销毁。
- 使用
模型-视图(Model/View)模式速览
当数据来自数据库、网络或需要排序/过滤时,请优先使用 Model/View。
-
模型类型:
QStandardItemModel
:通用树状模型。QStringListModel
:简单字符串列表。- 自定义模型:继承
QAbstractListModel
/QAbstractTableModel
。
-
视图绑定:
auto model = new QStandardItemModel(0, 2, this); model->setHorizontalHeaderLabels({"名称", "类型"});auto item = new QStandardItem("Qt Widgets"); item->setEditable(false); model->setItem(0, 0, item);tableView->setModel(model); tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
-
排序与过滤:使用
QSortFilterProxyModel
。 -
委托:自定义单元格渲染可继承
QStyledItemDelegate
。 -
多模型联动:
- 使用
QDataWidgetMapper
将模型数据与表单控件绑定,实现主从界面。 QItemSelectionModel
可在多个视图之间共享选择状态(例如列表 + 详情面板)。
- 懒加载与分页:重写
fetchMore()
与canFetchMore()
,适用于后端分页或无限滚动场景。 - PySide6/PyQt6 提示:Python 中可继承
QAbstractTableModel
并实现roleNames()
以便与 QML 集成。
常见问题与解决方案
1. QListWidget
控制 QStackedWidget
页面切换
需求:左侧菜单列表点击后切换右侧内容页。
实现步骤:
-
创建列表与堆栈:
auto list = new QListWidget; auto stack = new QStackedWidget;list->addItems({"概览", "设置", "关于"}); stack->addWidget(createOverviewPage()); stack->addWidget(createSettingsPage()); stack->addWidget(createAboutPage());
-
连接信号槽:
connect(list, &QListWidget::currentRowChanged,stack, &QStackedWidget::setCurrentIndex); list->setCurrentRow(0); // 默认显示第一页
-
若需同步页面标题:
connect(list, &QListWidget::currentTextChanged, this, [this](const QString& text){ui->titleLabel->setText(text); });
-
PySide6 版本:
list.currentRowChanged.connect(stack.setCurrentIndex) list.setCurrentRow(0)
常见坑:
- 需要初始化
list->setCurrentRow(0)
,否则stack
保持默认页。 - 若使用自定义信号,应确保
QStackedWidget
传入的是 索引 而非指针。 - 切换时需要保存状态,可在
stack->currentWidget()
强制QVariant
保存并恢复。
2. QTableWidget
行点击高亮但不触发槽
- 确认连接的是
itemClicked(QTableWidgetItem*)
或cellClicked(int, int)
。 - 检查是否设置了
setEditTriggers(QAbstractItemView::NoEditTriggers)
防止进入编辑状态被拦截。 - 若使用了
QSortFilterProxyModel
,请连接代理的信号。
3. 批量更新控件状态(如表单重置)
-
遍历子控件:
for (auto lineEdit : findChildren<QLineEdit*>()) {lineEdit->clear(); } for (auto checkBox : findChildren<QCheckBox*>()) {checkBox->setChecked(false); }
4. 界面卡顿与阻塞
- 长耗时任务放入
QThread
或使用QtConcurrent
,在主线程通过信号更新 UI。 - 使用
QProgressDialog
或自定义 overlay 提示进度。
5. 国际化(i18n)
-
使用
tr("文本")
包裹字符串。 -
运行
lupdate
生成.ts
翻译文件,linguist
编辑并导出.qm
。 -
在
main()
中加载:QTranslator translator; translator.load(":/i18n/app_zh_CN.qm"); app.installTranslator(&translator);
6. 样式表(QSS)不生效或部分控件失效
- 排查步骤:
- 确认选择器路径正确(如
QPushButton#primaryButton
),并在 UI 中调用setObjectName
。 - 检查
setStyleSheet
的调用顺序,后调用的样式会覆盖之前的设置。 - 若使用
qrc
,确认资源在.qrc
中登记且路径带前缀:/
。 - 组合控件(如
QComboBox
)需要同时设置子控件伪状态(例如QComboBox QAbstractItemView
)。
- 确认选择器路径正确(如
- 调试技巧:临时设置
* { outline: 1px solid magenta; }
辅助定位。
7. Dock 布局状态无法恢复
-
确保在
MainWindow
构造函数末尾调用restoreState(settings.value("dock_state").toByteArray())
。 -
在关闭前保存:
void MainWindow::closeEvent(QCloseEvent* event) {QSettings settings("MyOrg", "DockDemo");settings.setValue("dock_state", saveState());settings.setValue("geometry", saveGeometry());QMainWindow::closeEvent(event); }
-
若版本升级新增 Dock,需要在
restoreState
前调用setDockNestingEnabled(true)
并确保 Dock 名称唯一。
8. 自定义委托编辑后数据不更新
-
在委托的
QStyledItemDelegate::setEditorData
与setModelData
中同步数据。 -
触发提交:
void CustomDelegate::setModelData(QWidget* editor, QAbstractItemModel* model,const QModelIndex& index) const {auto line = qobject_cast<QLineEdit*>(editor);if (!line) return;model->setData(index, line->text(), Qt::EditRole); }
-
需要在编辑器的
editingFinished
信号中调用emit commitData(editor); emit closeEditor(editor);
。 -
在视图中设置
view->setItemDelegate(new CustomDelegate(view));
。
9. 高 DPI 缩放与模糊
-
在
main()
中启用高 DPI 属性:QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
-
资源图片应使用矢量(SVG)或提供
@2x
、@3x
。 -
对自绘控件,在
paintEvent
中使用devicePixelRatioF()
调整绘制尺寸。
10. 多线程更新 UI 崩溃
- 原因:Qt Widgets 只能在主线程操作。
- 解决:
- 在线程中发射信号,主线程连接
Qt::QueuedConnection
。 - 或使用
QMetaObject::invokeMethod(widget, [=]{ widget->setValue(val); }, Qt::QueuedConnection);
- 若使用
QtConcurrent::run
,在回调中通过QFutureWatcher
的信号更新 UI。
- 在线程中发射信号,主线程连接
性能调优与调试技巧
- 布局性能:减少嵌套层级,必要时使用
QWidget::setUpdatesEnabled(false)
批量更新。 - 绘制性能:重写
paintEvent
时尽量使用QPainter
合理裁剪,避免每帧重新加载资源。 - 调试工具:
Qt Creator
的 Analyze > GammaRay(第三方)可实时查看控件树。- 使用
qDebug()
或QLoggingCategory
跟踪信号槽。
- 样式调试:使用
setStyleSheet("* { outline: 1px solid red; }")
定位控件占位。 - 实战建议:
- 配合
QElapsedTimer
统计渲染与数据加载耗时,输出到日志定位瓶颈。 - 对于模型数据庞大场景,开启视图的
setUniformRowHeights(true)
可减少重复测量。 - 在多语言项目中预加载字体并调用
QFontDatabase::addApplicationFont
以避免首帧卡顿。
- 配合
附录:推荐资源与进阶阅读
- 官方文档:https://doc.qt.io
- Qt Examples:Qt 安装目录
Examples/
下的 Widgets 演示。 - 社区资源:
- KDAB Blogs(性能与高级主题)
- Woboq blog(Qt 深入文章)
- PySide 官方教程(Python 开发者)
- 书籍推荐:
- C++ GUI Programming with Qt 5(Jasmin Blanchette)
- Advanced Qt Programming(Mark Summerfield)
🧭 延伸方向:如需进一步掌握 QML/Qt Quick、跨平台部署、混合渲染(OpenGL/Vulkan 与 Widgets 结合)等主题,可在官方文档的
Qt Quick
与Qt for Device Creation
章节继续探索。