在刚开始做 Qt 项目时,很多人第一次新建类都会被这个界面搞懵:

  • QObject
  • QWidget
  • QMainWindow
  • QQuickItem
  • <Custom>

看上去都是“基类”,但问题是:它们到底有什么区别?我这个类到底该继承谁?

尤其是在模仿老师项目或者自己搭项目的时候,经常会遇到这种情况:

  • 有的时候新建类选 QObject
  • 有的时候又选 QWidget
  • 主窗口又是 QMainWindow
  • 还有些类根本不显示界面

如果一开始没有把这个问题想清楚,后面写代码时就很容易乱。
所以这篇文章就专门来解决一个问题:

Qt 新建类时,Base class 到底怎么选?

我不打算只讲概念,而是尽量从“这个类在项目里到底扮演什么角色”来讲清楚。

1. 先记住一个最核心的判断标准:这个类到底是“干活的”还是“显示界面的”?

很多初学者一看到基类,就想着“哪个功能更强就选哪个”。
其实不是这样。

在 Qt 里,选基类最重要的不是看谁“更高级”,而是看:

你这个类到底是拿来处理逻辑的,还是拿来显示界面的。

你可以先把 Qt 里的类粗略分成两大类:

第一类:不负责显示界面,只负责处理逻辑

比如:

  • 错误处理类
  • 网络通信类
  • 数据管理类
  • 配置读取类
  • 定时任务类
  • 控制器、管理器、服务类

这类类通常不需要在屏幕上显示出来,它们只是默默在后台“干活”。

这种情况下,通常优先考虑的就是:QObject

第二类:需要显示在界面上的类

比如:

  • 一个按钮区域
  • 一个设置页
  • 一个自定义面板
  • 一个弹窗
  • 一个主窗口

这类类是用户能直接看到、点击和交互的。

这种情况下,通常就要从:

  • QWidget
  • QMainWindow
  • QQuickItem

里面选。

所以最简单的一句话就是:

不显示界面,多半选 QObject;要显示界面,再看是普通界面还是主窗口。

这就是最底层的判断逻辑。

2. QObject:适合“后台逻辑类”,不负责显示界面

QObject 可以说是 Qt 里非常基础、非常常用的一个类。
它本身不是一个界面控件,也不会显示在窗口里,但它有很多 Qt 非常核心的能力,比如:

  • 对象树和父子关系管理
  • 信号与槽机制
  • 事件机制
  • 内存自动管理的一部分支持

所以在项目里,凡是那些不需要长在界面上、但又想利用 Qt 机制的类,很多都适合继承 QObject

什么样的类适合选 QObject?

比如下面这些名字,一看就很适合 QObject

  • ErrorHandler
  • FileManager
  • DatabaseManager
  • ConfigReader
  • NetworkClient
  • TaskController

你会发现,这些类有一个共同点:

它们不是拿来给用户看的,而是拿来给程序干活的。

就拿 ErrorHandler 来说,这个类从名字上就能看出来,它更像是一个“错误处理器”或者“异常处理模块”。
它的职责通常是:

  • 接收错误信息
  • 分类错误
  • 记录日志
  • 发出提示信号
  • 通知其他模块处理

它本身不是一个按钮,不是一个窗口,也不是一个页面,所以这时候选 QObject 就非常合理。

为什么这种类不该选 QWidget?

因为 QWidget 是界面类。
如果你只是想写一个逻辑处理类,却继承了 QWidget,就相当于你给一个“后台工作人员”硬套了一个“窗口外壳”,这在设计上是不合适的。

说白了就是:这个类明明不需要显示,结果你却把它做成了一个界面类。

这样做的问题有两个:

第一,语义不清楚。
别人一看你继承 QWidget,会默认觉得这是个界面类。

第二,没必要增加界面类的负担。
逻辑类就应该尽量保持轻量,不要无缘无故背上界面的包袱。

一句话记忆 QObject

凡是“管理器、处理器、控制器、服务类、数据类”,大多数先考虑 QObject。

3. QWidget:适合“普通界面类”,它是你最常用的页面和组件基类

如果说 QObject 是“后台干活”的,那么 QWidget 就是“真正站到前台”的。
它表示的是一个可见的界面组件,也就是说,用户是可以在窗口里看到它的。

很多初学者做 Qt 项目时,实际接触最多的界面类,往往就是 QWidget

QWidget 最适合做什么?

适合做这些“普通界面”:

  • 一个设置页面
  • 一个登录页面
  • 一个信息展示面板
  • 一个自定义小组件
  • 一个弹出的普通窗口
  • 一个嵌入到其他窗口中的界面区域

你可以把 QWidget 理解成:

“界面上的一块区域”或者“一个普通窗口单元”

它不一定是整个程序最外层的大窗口,它更多像是界面中的一个组成部分。

什么情况下该选 QWidget?

当你这个类满足下面这些特征时,通常就该考虑 QWidget

  • 这个类要显示在界面上
  • 用户能看到它、点到它
  • 它可能放按钮、标签、输入框、列表这些控件
  • 它更像是一个“页面”或“模块”

比如:

  • LoginWidget
  • SettingPage
  • UserInfoWidget
  • ControlPanel
  • ResultWidget

从这些名字你就能感觉到,它们更像是界面的一部分,而不是纯逻辑类。

QWidget 和 QObject 的本质区别

最简单的区别就是:

  • QObject:有 Qt 机制,但不负责界面显示
  • QWidget:既有 Qt 机制,又是一个可显示的界面对象

所以你可以把 QWidget 看成是“带界面能力的更具体的一类对象”。

一句话记忆 QWidget

只要这个类是“给用户看的一个普通页面或组件”,优先考虑 QWidget。

4. QMainWindow:适合“整个程序的主窗口”,不是普通页面都该用它

很多人刚学 Qt 时,会觉得 QMainWindow 好像比 QWidget 更厉害,于是新建界面就想直接选 QMainWindow
这其实是一个很常见的误区。

QMainWindow 的确是一个窗口类,但它不是给你随便拿来做任何界面的。
它更适合用来表示:

整个应用程序最外层、最核心的主窗口。

什么叫主窗口?

比如一个桌面软件启动后,最外面的那个总界面,通常会有这些东西:

  • 菜单栏
  • 工具栏
  • 状态栏
  • 中央工作区
  • 停靠窗口

这种结构就很符合 QMainWindow 的设计思路。

也就是说,QMainWindow 更适合那种“像一个完整软件壳子”的界面,而不是普通的小页面。

什么情况下该选 QMainWindow?

比如你要做:

  • 程序启动后的主界面
  • 整个系统的主操作台
  • 带菜单栏和状态栏的软件主窗口
  • 类似 IDE、管理系统、工具软件的主框架

这些都适合 QMainWindow

为什么不能随便把页面都做成 QMainWindow?

因为 QMainWindow 的定位太“重”了。

它不是给你做每个子页面的。
如果你只是做一个设置页、一个登录页、一个功能模块页,却继承 QMainWindow,就会显得非常笨重,而且结构也不清晰。

你可以这样理解:

  • QMainWindow:像“整栋楼”
  • QWidget:像“楼里的某个房间”

显然,不是每个房间都要建成一整栋楼。

一句话记忆 QMainWindow

整个程序最外层的主窗口,用 QMainWindow;普通页面别乱用。

结语:选基类,本质上是在选“这个类的身份”

很多人刚开始学 Qt,会把“继承谁”看成一个语法问题。
其实它更像是一个设计问题。

因为你选的不是一个单纯的名字,而是在决定:

这个类在项目里到底扮演什么身份。

  • 它是后台逻辑人员,还是前台界面人员?
  • 它是普通页面,还是整个程序的大框架?
  • 它是 Qt Widgets 项目的一部分,还是 QML 体系的一部分?

一旦把“类的身份”想清楚了,基类的选择其实就没那么难了。

最后再用一句最接地气的话总结:

不显示界面,就先想 QObject;显示普通页面,就选 QWidget;整个软件主窗口,才选 QMainWindow。

这样基本就不会错得太离谱。

0voice · GitHub

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐