在Qt里做自定义控件,很多人前面不是不会继承QWidget,而是封装完以后不知道该怎么让Designer认出来。这个问题其实有两条路,一条是先用标准控件做占位,再提升成自己的类,另一条是直接给Designer写自定义控件插件。Qt官方手册把这两条路分得很清楚,所以真正稳妥的做法,不是上来就写插件,而是先分清你现在只是想让.ui能用这个类,还是想让它直接出现在Designer左侧控件箱里。
一、Qt怎么封装自定义控件
先不要一开始就把目标定成“必须在Designer里可视化编辑”。更稳的做法,是先把控件本身封装成一个正常可用的QWidget子类,把属性、信号和槽先收干净。因为Qt官方对Designer自定义控件插件的说明写得很明确,插件只是把你已经写好的控件暴露给Designer,不是替你完成控件本身的封装。
1、先把控件写成一个独立类
先用QWidget或某个现成控件做基类,把自己的界面、属性和交互逻辑封到一个单独类里。Qt官方在说明提升和插件时都反复强调,Designer最终使用的是你自己的控件类,所以类本身先写稳,后面两条路都能走。
2、属性要尽量按Qt属性体系来写
如果你后面希望Designer能看到并编辑这些属性,就不要只写普通成员变量。Qt官方在自定义控件接口说明里专门提到,Designer会根据控件暴露出来的属性信息去显示和生成对应内容,所以前面封装时就要按标准属性方式整理。
3、尺寸和默认外观也要先给出来
Qt官方说明里提到,如果自定义控件没有合适的size hint,插件侧还要在domXml里额外补默认几何信息。换句话说,控件本身如果连基本尺寸行为都不稳定,后面放进Designer里通常也不好用。
4、只想让.ui正常生成代码时优先用提升
如果你现在只是想在表单里放一个“看起来差不多”的占位控件,后面由uic生成正确头文件和类名,那更省事的做法通常不是写插件,而是先用Promote to。Qt官方明确说明,这条路就是给“Designer当下用不到真实控件,但应用里要用真实类”准备的。
二、Qt自定义控件在Designer里怎么显示
这里最容易混淆的是“能在.ui里用”和“能在Designer控件箱里看到”其实不是一回事。Qt官方手册写得非常清楚,前者可以靠提升完成,后者则要靠插件机制。也就是说,Designer里怎么显示,关键要先分清你要的是占位显示,还是完整注册。
1、只做占位显示就用【Promote to】
先在表单里放一个基类相近的标准控件,然后在右键菜单里选【Promote to...】。接着填类名和头文件,点【Add】,再点【Promote】。Qt官方文档明确说明,这样Designer会把这个标准控件当成你的自定义类来生成代码,而且以后右键菜单里还会继续出现这条提升项。
2、要出现在控件箱里就写Designer插件
如果你希望这个控件像QPushButton一样直接出现在Designer左侧控件箱里,那就不能只做提升,必须实现QDesignerCustomWidgetInterface。Qt官方说明里已经把这套接口列得很完整,包括名称、分组、提示、头文件、图标、是否容器和createWidget这些信息。
3、插件项目要按Designer插件方式构建
Qt官方给了插件工程的正式写法。用CMake时,需要qt_add_plugin,并链接Qt::UiPlugin;如果插件还要访问更多Designer接口,则改用Designer相关链接。也就是说,Designer里能不能显示,不只是代码类写对就够了,工程本身也得按插件规则编。
4、插件放到正确目录里才会被Designer载入
Qt官方明确说明,Designer启动时会在插件搜索路径下找designer子目录,通常放在QTDIR下的plugins/designer目录里;也可以通过QT_PLUGIN_PATH影响搜索路径。所以控件写好了却不显示,先别急着怀疑接口实现,路径没放对也是高频原因。
三、Qt里先用提升还是直接写Designer插件
这一步最容易做反。很多人只是想让表单先能跑起来,却一上来就写插件,结果工程、安装路径和接口描述一起变复杂;也有人明明希望控件在Designer里像正式控件一样出现,却还停在提升这条路上,后面每个表单都要手工补一次类名和头文件。更稳的判断方法其实很简单,就是先看你现在要解决的是“生成代码”还是“扩展Designer”。Qt官方文档本身就是按这条边界来区分提升和插件机制的。
1、项目还在早期,先用提升
如果控件刚封装好,接口还可能继续改,或者团队只是想先把.ui和业务代码串起来,用【Promote to...】通常最省时间。因为这条路不要求你立刻维护插件工程,也不要求控件马上进入控件箱。
2、团队要长期复用,再写插件
如果这个控件已经比较稳定,而且后面很多表单、很多人都会用它,那直接做成Designer插件会更顺。这样控件可以直接出现在控件箱里,属性、信号和槽也会按真实控件方式暴露出来。
3、控件很特殊时先判断是不是还适合提升
Qt官方文档提到,提升更适合那些和标准控件API接近的类;如果你的控件和标准控件差异很大,或者本身就是容器、多页控件这类更复杂对象,那继续拿标准控件做占位就会越来越别扭,这时更适合走插件。
总结
Qt自定义控件这件事,说到底不是先选技术名词,而是先看你的目标是什么。只想让.ui正常引用自己的类,用【Promote to...】就够了,路径短,改起来也快。真想让控件在Designer里像正式控件一样出现,再去实现QDesignerCustomWidgetInterface、按插件工程去编译,并把插件放到Designer能找到的位置。把这层分工先想清,后面无论是封装控件还是接入Designer,都会顺很多。