ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

重学Qt常用控件14讲:从零写代码吃透控件原理与实战

重学Qt常用控件14讲:从零写代码吃透控件原理与实战 这次我们来看一套“重学 QT”体系里的第 02 章常用控件14 讲。整个章节配套视频、源码和详细笔记学习方式强调“从零一行行写代码”不是打开 Qt Designer 拖两个控件就完事。这个定位值得单独拿出来讲很多 Qt 开发者的真实状态不是不会用 QPushButton而是对 QPushButton 背后的父子对象、布局策略、信号槽类型匹配和事件循环没有形成完整的知识闭环。控件是 Qt 桌面开发的入口也是后面做串口、图表、多线程、网络通信这些实战项目时必须反复使用的一层。把这一章啃透比急着去学 Model/View 或者 QML 更划算。先说结论如果你正在准备 Qt 面试、要维护老 QWidget 项目、或者用 Qt 做上位机但只能照抄 demo这一章建议整章重过一遍如果你是零基础且 C 语法还不熟先把指针、引用、const、lambda 基础补一补再进来。文章会按照“先看环境能不能跑、再用最小代码验证控件、最后按清单排查问题”的顺序展开尽量把 14 讲里最容易翻车的几个点说清楚。正文比较长建议先收藏。1. 常用控件章节核心信息速览项目说明章节定位重学 QT 基础篇第 02 章承接第 01 章环境与基础进入控件实战课时体量常用控件共 14 讲每讲围绕一组 Qt Widgets 控件展开课程资料视频教程、配套源码、详细笔记代码方式从零一行行写代码不是直接用 Designer 拖拽主要功能QWidget 常用控件创建、属性设置、信号槽关联、布局组合适合平台Windows、Linux 下 Qt Widgets 桌面应用硬件要求普通 CPU 电脑即可最好能装 Qt Creator语法基础需要 C 基础至少会用类、指针、虚函数、lambda延续方向信号槽机制、布局管理、样式表、Model/View、多线程 UI 更新、QCustomPlot/QChart 绘图先说一个容易误判的点14 讲不代表只有 14 个控件。Qt 基础控件数量很多课程更常见的组织方式是把同族控件放在一起讲比如 QLineEdit 和 QTextEdit 都是文本输入QRadioButton、QCheckBox、QPushButton 都属于按钮族。学的时候要看懂基类和派生类的关系而不是孤立地记每个类的 API。下面给出的学习路径和验证清单也建议按这个思路去套不必逐行背文档。视频、源码、笔记三者怎么分配优先级新手最容易犯的错是只看视频不动手。14 讲的节奏合适哪怕每讲只有十几分钟也建议每讲结束后关掉视频对照笔记里的目标从零写一遍核心代码。源码不是用来直接打开的是用来做“最后对照”的。这样一套流程下来代码量不多但是每个控件都过了一遍真实使用场景后面遇到问题也更容易定位是布局问题、信号槽问题还是控件生命周期问题。2. 为什么要“重学”而不是“初学”控件很多 Qt 教程讲控件只讲一句“创建一个按钮然后 connect 它的 clicked 信号”但你在真实项目里会立刻碰到几个追问这个按钮是 new 出来还是放在栈上要不要传 parent如果不传 parent按钮关闭后会不会内存泄漏按钮被 Layout 接管之后布局对象和父窗口谁负责删除这些问题在“用 CtrlC、CtrlV 写 Qt”的时候不会暴露一旦自己从零构建一个窗口马上就会卡住。第 02 章强调从零一行行写代码本质是在逼你建立自己的控件知识结构。一个控件从生到死至少要过这几步构造时可以传 parent但也可以在后续任意时刻 reparent设置属性前要想清楚是字符串、数值还是枚举addWidget 布局后控件尺寸由 layout 管理控件要被 show 或者被父窗口带入显示状态控件发出 clicked、textChanged、currentIndexChanged 等信号时对应的槽函数要在正确的对象和线程里执行窗口销毁时子控件会被递归销毁但是如果控件没有父对象就必须自己保证释放。Qt 控件的类层级也值得重新看一遍。QPushButton、QToolButton、QRadioButton、QCheckBox 都继承自 QAbstractButton而 QAbstractButton 又继承 QWidget。只要理解了 QAbstractButton 提供了 setText、setIcon、click、setCheckable 这些公共能力和 clicked、pressed、released、toggled 这些信号后面遇到任何“按钮类控件”都会自动联想过去。同理QListWidget、QTableWidget、QTreeWidget 虽然形态差别很大实际上都建立在 item widget 的模型之上。先掌握基类再区分派生类差异是效率最高的学习路径。从面试角度说控件也是 Qt 开发最容易被细问的地方。面试官很少问“QLabel 的构造函数会传入 parent 吗”但如果聊你做过多少个窗口大概率会问怎么动态生成一组按钮、怎么在一个界面里嵌套多个 QTabWidget、表格里成百上千行数据为什么卡、信号槽断开怎么做、线程里能不能直接改 QLabel 文本。这些问题不会只考“认识某个控件”而是考控件背后的对象模型和事件循环。第 02 章把控件本身的基础打牢后面很多问题都能追回到这一章。3. 适用场景与学习边界不是所有人都需要以这一章为主路线。第 02 章适合四类读者第一C 基础还行但 Qt 经验基本靠复制 demo现在需要独立承担窗口模块第二做工业上位机或桌面工具的开发界面主要是 QWidget/QDialog需要把控件用得更规范第三准备系统补 Qt 基础的面试者希望把常用控件、信号槽、源码结构串成完整知识线第四要带新人、写内部培训资料的技术负责人可以参考 14 讲结构做练习清单。如果不满足前提建议先不要碰这章完全不会 C 的读者先补变量、类、继承、指针、STL 基础再回来看目标是 QML/Qt Quick 移动端或嵌入式 HMI 的读者Widgets 控件虽然能辅助理解概念但主路线应转向 QML 类型系统只想做一次性小工具、不考虑工程维护的读者用 Designer 拖拽确实更快这章的方法是帮你建立长期可维护能力短期看“性价比”反而不高。还要说明一个边界第 02 章是控件使用不包含完整的自定义控件绘制体系。如果要做炫酷皮肤、重绘仪表盘、地图轨迹、时域波形图还需要后续的 QPainter、QPen/QBrush、事件重写和 QCustomPlot/QChart 专题。常用控件这一层解决的是“窗口搭得出来”但一个窗口的视觉细节、动画流畅度、超大列表性能属于图形绘制和 Model/View 优化问题。学完这章不要误以为自己已经把 Qt 图形全部掌握了。合规边界的提醒也要放在前面。无论项目用视频里的源码还是自己写的控件逻辑如果涉及真实业务系统都要检查 Qt 开源版协议、源码依赖库的许可证以及最终产品是否需要开源。Qt 按 LGPL 等协议使用时通常需要允许用户替换 Qt 库具体条款要按照实际版本和商用方式确认。此外把控件用于工控或数据采集界面时严禁直接连接未经授权的内网资源凡是涉及他人文本、图片、字体、图标素材的都要确保有授权。4. 环境准备把 Qt 跑通再谈控件这章说的“环境”不复杂但对新手来说一个明显问题是看视频时讲师用的版本和本地不一致导致 API 明明一样编译却各种报错。Qt 5 和 Qt 6 都支持 QWidget 常用控件常用控件 API 多数兼容但 CMake 配置方式、高 DPI 默认行为、部分头文件位置有差异。视频配套源码基于哪个版本最好先看笔记里的要求。没有明确说明时我建议 Qt 5.15.2 或 Qt 6.5 之后的 LTS 版本都可以二选一后尽量保持一致。安装 Qt 工具链时要关注的不是“默认下一步”而是组件勾选。使用 Qt Widgets 应用至少需要当前平台的编译器支持Windows 常用 MSVC 或 MinGWLinux 用 GCC。安装 Qt 时把对应编译器套件、Qt Debugger、Qt Creator、Sources 勾上宁可磁盘多占几 GB也不要等到编译时才发现缺少 Symbols 或调试器。初学者最怕的报错“could not find the qt platform plugin windows”“qt.qpa.plugin: could not load the Qt platform plugin”通常不是控件代码问题而是环境没有配对。先做一个不依赖任何自定义控件的空白窗口。新建项目时选 Qt Widgets Application也可以手动建立目录和源文件。最简单的 main.cpp#include QApplication #include QLabel int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label(控件章节环境验证); label.resize(320, 120); label.show(); return app.exec(); }.pro 工程文件可以很简单QT widgets CONFIG c17 TARGET env_check TEMPLATE app SOURCES main.cpp如果使用 CMakeQt 6 的基础 CMakeLists.txt 可以这样写cmake_minimum_required(VERSION 3.16) project(env_check LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) find_package(Qt6 REQUIRED COMPONENTS Widgets) qt_add_executable(env_check main.cpp) target_link_libraries(env_check PRIVATE Qt6::Widgets)编译成功并弹出窗口说明 qmake/CMake、编译器、Qt 库、插件链已经通了。如果运行后没有窗口而是报错可以先检查两个方向构建时用的 Kit 是否和安装的 Qt 编译器一致程序运行时是否能找到 Qt 的 plugins 目录。开发环境下Qt 的 bin 和 plugins 路径通常已经写入安装器如果手动拷贝 exe 到别的目录运行就要用 windeployqt 把 Qt 运行库和 platforms 目录带过去。5. 从零一行行写代码每讲最好这样拆解第 02 章有 14 讲如果用屏幕看视频会看到讲师在代码编辑器里从空文件开始敲。很多人误以为这种演示只是“为了显得认真”实际上这是一个很高效的拆解法不要一次写整个窗口也不要直接在 Qt Creator 里用双击生成 UI 文件。正确方式是把每一讲的大目标拆成小步每步能看到编译和运行结果。以按钮和文本输入为例可以把一个简单联动拆成几步第一步创建 QWidget 作为主窗口第二步放一个 QPushButton、一个 QLineEdit、一个 QLabel第三步设置水平和垂直布局明确控件在窗口缩放时的伸缩行为第四步连接按钮的 clicked 信号让 QLabel 显示 QLineEdit 当前文本第五步编译运行验证点击效果第六步再增加边界情况比如输入为空时提示或者禁用按钮。每一步都是可以运行的而不是写完一个几百行的文件再去找错误。为什么强调一行行写代码而不是直接使用 Designer因为 Designer 生成的 .ui 最后也会编译成代码但控件之间的 parent、objectName、layout 关系被可视化了你容易失去对“代码如何组织”的敏感。运行期动态创建控件时没有 .ui 帮你管理父子关系、信号槽、布局层级都必须写清楚。先练习纯代码之后再学 .ui 才能真正理解 UI 文件是怎么工作的。反过来如果你已经熟练 Designer也建议在工程里查看 ui_xxx.h 里生成的 setupUi 函数这比任何教程都更能还原控件代码结构。再给一个纯代码的练习模板。目标是用 QSlider 控制 QLabel 显示数字看控件之间的数值联动#include QApplication #include QWidget #include QSlider #include QLabel #include QVBoxLayout int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.setWindowTitle(Slider 到 Label 联动); QSlider *slider new QSlider(Qt::Horizontal); slider-setRange(0, 100); slider-setValue(30); QLabel *label new QLabel(30); label-setAlignment(Qt::AlignCenter); // QSlider::valueChanged 不存在重载写法最稳 QObject::connect(slider, QSlider::valueChanged, label, [label](int value) { label-setText(QString::number(value)); }); QVBoxLayout *layout new QVBoxLayout(window); layout-addWidget(slider); layout-addWidget(label); window.show(); return app.exec(); }这段代码正确连接到 label但只有当你确认了 QSlider 的 valueChanged 参数是 int 之后才敢这么写。如果换成 QSpinBox它的 valueChanged 信号在 Qt 中有重载直接用 QSpinBox::valueChanged 作为函数指针会出现歧义。课程在讲“一行行写代码”时这类细节就是最容易暴露基础是否牢固的地方。配套源码到手之后不要先急着全看。每讲源码可能有多个文件先只看 main.cpp 或单个 widget 的实现看懂它创建了哪几个控件、每个控件构造函数里的 parent 是谁、哪些控件被 addWidget 了、connect 的发送者和接收者是谁。如果能在不看源码的情况下自己复现同一逻辑再去对照源码差异点就是这讲最值得重点理解的坑。6. 常用控件的学习地图与验证清单第 02 章 14 讲如何分配没有统一答案但常用控件通常会被划分为显示类、按钮类、文本输入类、数值输入类、列表表格树类、容器和窗口结构类。每一类抓的核心点不一样学习时用的验证方法也不一样。显示类控件中QLabel 最典型常用属性是 text、alignment、wordWrap还有 pixmap 显示图片信号比较少主要靠外部代码改变它的内容。学习 QLabel 的时候要重点验证“文本变化后布局如何更新”“长文本不换行会怎样”“图片和缩放模式怎么配合”。QProgressBar 可以归入显示与反馈它一般依赖外部代码更新 value适合在后续多线程任务里使用。按钮类控件以 QPushButton、QRadioButton、QCheckBox、QToolButton 为代表。它们都能通过 setText、setIcon 设置界面setEnabled 控制可用性。QPushButton 最常用 clickedQRadioButton 和 QCheckBox 则适合用到 toggled 信号。做验证的时候可以把三个按钮放到 QButtonGroup 里观察单选和互斥行为能不能符合预期。文本输入类控件要分开对待。QLineEdit 是单行输入学习重点包括 placeholderText、setEchoMode用它做密码框、搜索框很常见QTextEdit 是多行富文本编辑器它可以展示纯文本、HTML 或 Markdown实践项目里也大量用来显示串口日志、聊天记录、文本日志。这里最容易出问题的是“输入事件触发频率”。在 QLineEdit 的 textChanged 信号里做每次按键处理槽函数会很频繁执行所以要掌握什么时候用 editingFinished什么时候用 textChanged。数值输入类控件中QSpinBox、QDoubleSpinBox、QSlider、QDateTimeEdit 都很常用。QSpinBox 与 QSlider 经常做联动用来设置电机速度、音量、阈值等参数。QDateTimeEdit 在项目中常与 QCalendarWidget 配合用来做日期区间选择。学到这里可以尝试做一个“参数设置区”用 QSpinBox 设置数量用 QSlider 快速拖拽同时用一个 QLabel 实时显示最终值这比单独练习一个控件更有用。列表表格树类控件是很多工程软件的界面核心。QListWidget 适合简单列表QTreeWidget 适合树形结构QTableWidget 适合行列表格。它们的快速 demo 都不难addItem、setItem、setCellWidget、currentRow 这些基础 API 很容易上手。但工程里会出现大量行的列表这时只靠 item widget 会卡顿之后需要了解 Model/View 和自定义委托。第 02 章如果只要求“能用”你至少要知道 QTableWidget 的行列、表头和 item 选择怎么取如果要处理几十万行那不能停留在 item widget要往 QTableView 和 QAbstractTableModel 方向走。容器类和窗口结构类包括 QGroupBox、QTabWidget、QSplitter、QScrollArea、QMenuBar/QToolBar/QStatusBar。它们的核心作用是组织界面。验证时重点看两件事加入子控件后布局是否替换、窗口拉伸时容器内部的控件到底按什么策略变化。QGroupBox 可以给一组单选按钮提供分组边界QTabWidget 用来切页QScrollArea 可以包住超出可视区域的内容。只看单个控件外观不够必须拖到整体布局里去验证。每讲学完不要靠感觉判断“会了”可以用下面的问题自查控件你会不会写这些QPushButton/QRadioButton/QCheckBoxsetText、setEnabled、clicked、toggled、QButtonGroup 分组QLineEdit/QTextEdittext、placeholderText、echoMode、textChanged、多行日志显示QComboBoxaddItem、currentIndexChanged、setEditable、获取当前文本QSpinBox/QSlidersetRange、setValue、valueChanged、数值联动QListWidget/QTableWidget/QTreeWidget增删条目、读取当前选中项、表头设置QTabWidget/QGroupBox/QSplitter动态加页、嵌套布局、拉伸比例QProgressBar/QLabel进度更新、文本/图片显示、样式表改变外观更直接的办法是反过来做题给一个需求不给控件名让你选择用什么控件。要求“下拉选一个方案右侧显示对应说明文字”你要想到 QComboBox QStackedWidget要求“左侧分类树、右上详细表格、右下日志”你要想到 QTreeWidget QTableWidget QTextEdit 加 QSplitter。这种“需求到控件”的映射能力才是 14 讲练完之后留下来的能力。7. 信号槽是控件练习里最绕的一环把常用控件练得差不多后最大的难点就集中在信号槽上。控件本身只是“带界面的对象”真正让界面动起来的是信号槽。第 02 章虽然主题是控件但每讲都脱离不了 connect所以要提前把信号槽的基础用法摸清。新版 Qt 推荐使用函数指针语法因为它在编译期就能检查信号和槽是否存在类型不匹配会直接报错。比如连接按钮点击和窗口关闭connect(button, QPushButton::clicked, this, QWidget::close);如果槽函数带参数信号参数必须能转换为槽参数。clicked 信号还有一个 bool checked 参数如果你使用QPushButton::clicked连接到无参 lambda编译通常没问题但如果你的 lambda 想接收 checked 状态就要写成[this](bool checked){ ... }。这些细节用旧版字符串形式的 SIGNAL/SLOT 宏可能到运行期才暴露新语法则更早发现问题。lambda 是控件练习里最灵活的连接方式。不过 lambda 默认不会延长 receiver 生命周期只负责执行逻辑。常见错误是在 lambda 里捕获了 this 或控件指针结果界面已经销毁线程回调却还在跑。处理办法是判断生命周期或者让发送者和接收者都挂在同一父对象上关闭窗口时整个对象树被释放。另一个小坑是 lambda 捕获了局部 QWidget 指针但如果该控件没有父对象它生命周期独立于窗口窗口关闭后它仍存活Lambda 执行时可能操作一个隐藏但不销毁的控件逻辑可能出乎意料。带重载的信号也是新手高频报错点。QComboBox 的 currentIndexChanged 有 int 和 QString 两个重载QSpinBox 的 valueChanged 在 Qt 中也有 int 和 QString 两种形式。直接用 QSpinBox::valueChanged 作为参数会得到“no matching member function for call to connect”之类的错误。解决方法是显式指定类型connect(spin, QOverloadint::of(QSpinBox::valueChanged), this, [this](int value) { label-setText(QString::number(value)); });Qt 6 中还提供了 qOverload 模板本质上也是在编译期选择正确的信号重载版本。学控件时遇到这种错误不要跳过它是在帮你理解 C 的函数指针类型和信号重载。信号槽还可以跨线程使用。第 02 章不要求你写多线程但要记住一个边界在工作线程里不能直接调用控件对象的 setText、show、hide 等方法因为 QWidget 只能在主线程操作。正确做法是把要传出的数据封装成信号发出来由主线程的槽函数更新 UI。如果未来在老项目里看到界面卡死、崩溃、偶发不刷新好多都和“线程里操作了控件”有关。这也是为什么基础篇后面会有事件循环和线程章节它们和常用控件是配套的。8. 生命周期、父子对象与控件释放写控件代码时“用指针 new 出来的控件到底由谁 delete”必须有一个统一答案。Qt 的父子对象机制约定给控件指定 parent父析构时会递归 delete 所有 child但如果你先 setParent 到一个窗口后来又把该控件 reparent 到另一个窗口所有权也会跟着变化旧的父对象不再替它释放。回忆一下常见代码。下面的写法把 label 作为 child 传给 windowwindow 生命周期结束时 label 自动释放QWidget *window new QWidget; QLabel *label new QLabel(我是子控件, window);这种写法简洁但如果不理解所有关系有人可能会在中途手动 delete label导致 window 析构时发生二次释放。另一个常见误区是把控件加入布局后再手动 delete。layout-addWidget 不是转移普通智能指针addWidget 在绝大多数情况下会把控件 reparent 到 layout 所在的 widget所以在布局容器销毁后再手动 delete 子控件同样会触发重复释放。内存管理的稳妥策略是所有 QWidget 对象尽量指定一个明确的 parent不必手工 delete。顶层窗口或需要延迟释放的对象使用 QObject::deleteLater。如果某个控件确实需要独立存在用 std::unique_ptr 或 QPointer 去管理时要格外小心。做练习时想要内存不炸最简单的规则是“从一个普通变量开始逐步 setParent 或 addWidget不要到处散落裸 new 后的孤儿控件”。生命周期还影响信号槽。如果 receiver 对象先于 sender 被销毁Qt 的信号槽连接默认会自动断开不会立刻崩溃这也是 Qt 对象树设计带来的好处。但如果接收者是 lambda 捕获的裸指针而该裸指针不是 QObjectQt 无法感知它什么时候失效。因此建议在 lambda 中尽量不捕获已经失控的控件裸指针或者在稍大逻辑里把捕获范围控制为 this、索引、值类型等回到主线程再用安全的 findChild 或成员指针操作。9. 配套源码和笔记拿到手后怎么用第 02 章的配套源码和详细笔记是这门课比其他纯视频内容更高效的部分但前提是你会用。一拿到源码不要直接全部拽进工程里编译先按目录结构认识文件名判断每个示例对应哪一讲。Qt 工程目录往往包含 .pro 或 CMakeLists.txt、main.cpp、widget 类文件有些示例还带 .ui。先看看主函数里都创建了什么控件再进入类实现里看构造函数的 setup 过程。笔记的推荐用法是“转译”成自己的表格。每学一个控件手写或维护一张卡片内容包含控件类名、头文件、典型构造函数参数、常用 setter/getter、发射的核心信号、需要注意的重载或父类特性。不要让笔记停留摘抄。例如 QListWidget 卡片上如果写了“常用信号 currentRowChanged”你就要配套写下“当前行变化时我可以结合 QStackedWidget 切页”这才是可迁移的知识。源码和视频的差集正是你的学习收获。先写跑不动再打开源码查先看视频演示再关掉视频把代码补全。如果源码能直接编译尝试刻意改造把单选按钮改成复选框把 QSpinBox 改成 QDoubleSpinBox把列表项点击改成一键删除。每处改动都可能引入新编译错误这些错误比视频里见过的正常执行过程更值钱。改错了不要立刻回滚先把报错信息读完整养成看“编译器前几行关键信息”和“构建输出尾部错误”的习惯。10. 常见问题与排查方法控件学习阶段的报错集中在几类环境插件错误、编译链接错误、运行期界面不显示、信号槽无响应、中文乱码。下面把最常碰到的现象和排查路径整理成表问题现象可能原因排查方式解决方案启动提示 could not find the Qt platform plugin windows系统找不到 Qt 的 platforms 插件看可执行文件旁有没有 platforms 目录检查 PATH 是否有 Qt bin开发环境检查 Kit 是否正确发布目录用 windeployqt 补齐插件Linux 下提示 qxcbconnection: failed to initialize xrandr 或 xcb 加载失败Qt xcb 平台插件或依赖库缺失启动带环境变量 QT_DEBUG_PLUGINS1查看缺失库安装 xcb、xkbcommon、xrandr 依赖Qt6 常需要 libxcb-cursor0窗口没有显示程序运行后很快退出忘记调用 showmain 中没有执行 app.exec在构造函数或 main 里检查 show所有顶层控件要 showmain 最后 return app.exec()点击按钮后槽函数不触发connect 写错、sender/receiver 生命周期问题、信号被覆盖在槽函数第一行加 qDebug检查 connect 是否执行使用新式 connect确认发送者对象是实际点击的按钮控件中文显示乱码Qt 5 MSVC 下源文件编码与编译器读取编码不一致检查源文件编码Qt 6 默认 UTF-8Qt5 MSVC 加 /utf-8 或统一 UTF-8 with BOM编译报错 undefined reference to vtable类中有 Q_OBJECT 但 moc 未生成检查是否启用 AUTOMOC 或 .pro 里 HEADERS 已包含头文件清理 build 目录重建检查 CMake AUTOMOC布局后控件大小不随窗口变化没设 Layout 拉伸比例或 sizePolicy拖拽窗口观察控件边界设置 QSizePolicy、layout-setStretch检查最小尺寸QSpinBox/QComboBox 信号用函数指针 connect 报类型不匹配信号有重载查看函数提示确定具体参数用 QOverload ::of 或 qOverload关闭窗口后后台进程不退出事件循环被其他顶层窗口或定时器占用观察关闭行为确认所有顶层窗口关闭、QApplication::quitOnLastWindowClosed 默认行为在这些问题里“ could not find the Qt platform plugin ”虽然是环境不是控件但它恰恰会在你最想看到控件时出现。开发环境跑 Qt 工程Qt 库和 plugin 的路径由编译器环境变量或安装器写入如果你手动把 debug 目录里生成的 exe 拷到其他地方运行exe 旁边没有 platforms 目录Qt 就会报这个错。解决方案不是到代码里改而是把 Qt 对应的插件目录一并复制。Windows 下使用windeployqt最可靠它会复制 Qt 运行库、插件和编译器运行库。Linux 下出现 qxcb 相关报错时执行一下项目的二进制往往能给出更具体的 xcb 库缺失。Qt 安装时自带的平台插件依赖系统图形库和系统自带的 Qt 库冲突也可能导致插件版本不一致。常用做法是设置QT_DEBUG_PLUGINS1输出插件细节方便快速定位。和控件代码关系不大但不解决它后面所有控件页面都无法弹出。如果点击按钮没有反应先用最简单的方法判断在槽里加qDebug() triggered;。如果点击时没有任何输出说明 connect 没生效或者发送者不对如果输出了但界面没变问题在槽实现逻辑或控件引用到了别处。信号槽连不上的一种隐蔽原因是运行时又给同一个控件执行 setObjectName 或换了代理导致事件被重新路由。遇到这类问题不要反复改 connect而是确认连接的是同一个控件实例。中文乱码问题在使用 MinGW 编译器时较少因为很多环境默认按 UTF-8 处理使用 MSVC 编译器时若源文件是 UTF-8 无 BOM 而 MSVC 默认按 GBK 读取字符串常量就会乱码。最稳妥的做法是Qt 5.15 MSVC 项目在 .pro 中增加msvc: QMAKE_CXXFLAGS /utf-8CMake 项目可以给 target 加上/utf-8编译选项或统一把源文件存成带 BOM 的 UTF-8。Qt 6 中情况改善很多但老代码迁移时仍要关注。编译报错出现 “undefined reference to vtable for” 时几乎都和 Q_OBJECT、moc 有关。Qt 的元对象系统需要在预处理阶段扫描类声明里的 Q_OBJECT 并生成 moc 文件。qmake 工程要把含有 Q_OBJECT 的类头文件加入 HEADERSCMake 要开启 AUTOMOC 或使用 qt_add_executable 提供的自动 moc。如果代码从旧文件夹拷贝过来没重新构建清理掉 build 目录后重新 qmake/cmake 往往就能恢复。11. 学完控件后向实战项目延伸的路第 02 章结束不代表控件就此学完。真正会写控件的标志不是能写出十几个单独窗口而是能把一组控件组合成一个可用工具。如果你是冲着“重学 QT”的完整路线来的接下来可以试着做一个综合小项目把前三章知识串起来。举个例子很多热词里提到的“qt 串口编程”“qt 时域图转换为频域图使用 qcustomplot 显示”都是典型控件应用。做一个串口调试助手界面层至少要用到 QComboBox 枚举可用串口、QTextEdit 显示收发的日志、QLineEdit 输入发送内容、QPushButton 控制打开和发送、QTimer 做轮询或超时控制。这些控件单独拉出来很简单但要配合 QSerialPort 的 readyRead 信号、QByteArray 数据转换、打开失败提示、接收缓冲区长度控制难度立刻就上来了。做一个信号频谱显示工具也一样底层是 FFT 计算界面层用 QCustomPlot 或 QChart 画曲线。要在界面上选择信号源、设置采样点数、点击开始采集、动态刷新曲线你仍然要依赖 QComboBox、QSpinBox、QPushButton、QTimer、布局以及信号槽协作。第 02 章的 14 讲如果没消化后面加再漂亮的绘图库也会感觉界面架构很乱。后续章节大概率会往更底层和更抽象的方向走。QPainter 自定义绘图、QEvent 事件处理、Model/View 架构、视图委托、线程与事件循环都会反过来影响你现在写控件的方式。学习建议是不要把章与章切得太开可以每学完一个新知识点就回到常用控件章节做一个小改造控件加一个自定义绘制按钮列表换成 QTableView model日志显示用多线程接收。这个循环越滚越大你对 Qt 的理解才会从“能运行”变成“能设计”。第 02 章真正的收获不只是看懂了几个控件的属性窗口而是建立了一套从对象创建、布局到信号关联的稳固定式。后面开会话框、主窗口、复杂业务界面时都可以沿用它。建议把视频、源码、笔记按“先动手再对照、对照后改造、改造后记录”的节奏排进学习计划整章过完后做一个小工具收尾再进第 03 章。那样你会发现后面的内容顺很多。
返回列表