14、Qt概述与环境搭建:Qt简介、Qt Creator安装、创建第一个Qt Widgets项目、信号与槽机制初探

好,咱们今天聊聊Qt。说实话,我最早接触Qt是在做嵌入式项目的时候,那时候被MFC折磨得够呛,一看到Qt的信号与槽机制,简直像发现了新大陆。你想想看,一个跨平台的C++图形界面框架,能让你写一套代码跑在Windows、Linux、macOS上,还能跑在嵌入式设备里——这不就是咱们C++程序员梦寐以求的东西吗?

Qt是什么?说白了,它是一套用C++写的应用程序开发框架。它不光能做界面,网络编程、数据库操作、多线程、XML解析、OpenGL渲染……几乎你能想到的功能,Qt都给你封装好了。我个人习惯把它叫做「C++界的瑞士军刀」。

Qt的版本与许可

Qt现在主要有两个版本:Qt 5和Qt 6。如果你是新学,我建议直接上Qt 6。为什么?因为Qt 6在性能、模块化、QML支持上都做了大幅优化。我在项目中遇到过从Qt 5迁移到Qt 6的情况,虽然API基本兼容,但有些旧模块被移除了,比如Qt WebEngine在Qt 6里改了不少东西。

许可方面,Qt有商业版和开源版(GPL/LGPL)。个人学习、开源项目用开源版完全没问题。商业项目如果不想开源,那就得买商业许可了。嗯,这里要注意:如果你用LGPL许可,动态链接Qt库是可以闭源的,但静态链接就得小心了。

Qt Creator安装

Qt Creator是Qt官方提供的IDE,轻量、好用、开箱即用。我个人习惯直接去Qt官网下载在线安装器。安装时选什么组件?我建议:

  • Qt 6.x 版本(选最新的稳定版)
  • MinGW 或 MSVC 编译器(Windows下MinGW省事,MSVC配合VS调试更强)
  • Qt Creator IDE(默认勾选)
  • Qt Charts、Qt Data Visualization(做图表和3D可视化时用)
  • Qt WebEngine(如果你要做内嵌浏览器)
小提示:安装路径不要有中文和空格,否则编译时可能出一些莫名其妙的错误。我曾经被这个坑过,折腾了一下午才发现是路径问题。

创建第一个Qt Widgets项目

安装好之后,咱们来创建第一个项目。打开Qt Creator,点击「New Project」→「Application (Qt)」→「Qt Widgets Application」。给项目起个名字,比如「HelloQt」,然后一路默认就行。

Qt Creator会自动生成几个文件:

  • main.cpp:程序入口
  • mainwindow.h:主窗口头文件
  • mainwindow.cpp:主窗口实现
  • mainwindow.ui:UI设计文件(可以用拖拽方式设计界面)
  • .pro文件:项目配置文件

咱们先不改代码,直接点运行(绿色三角)。如果一切顺利,你会看到一个空窗口弹出来。嗯,这就是你的第一个Qt程序了。

核心知识点:Qt Widgets应用程序基于事件循环。QApplication管理全局资源,exec()启动事件循环,窗口显示后等待用户操作。

信号与槽机制初探

信号与槽是Qt最核心的机制,也是它区别于其他框架的地方。你想想看,传统的回调函数有多麻烦?类型不安全、难以维护、耦合度高。Qt的信号与槽解决了这些问题。

简单来说:信号是某个对象发出的通知,是接收通知并做出反应的函数。用connect()把它们连接起来。

看个最简单的例子:

// 在mainwindow.h中声明槽函数
private slots:
    void onButtonClicked();

// 在mainwindow.cpp中连接信号与槽
connect(ui->pushButton, &QPushButton::clicked, 
        this, &MainWindow::onButtonClicked);

// 实现槽函数
void MainWindow::onButtonClicked()
{
    qDebug() << "按钮被点击了!";
}

这里ui->pushButton是你在UI设计器里拖进去的按钮。clicked是QPushButton自带的信号,当用户点击按钮时自动发射。onButtonClicked是你自己写的槽函数。

注意:信号与槽的参数类型必须匹配,或者槽的参数可以少于信号(多余的参数会被忽略)。但反过来不行。我曾经在项目中写错过参数顺序,编译通过了但运行时槽就是不触发,排查了半天才发现是参数类型不匹配。

Qt 5之后引入了新的connect语法,用函数指针代替字符串,编译期就能检查类型错误:

// 新语法(推荐)
connect(sender, &SenderClass::signalName,
        receiver, &ReceiverClass::slotName);

// 旧语法(不推荐,字符串容易写错)
connect(sender, SIGNAL(signalName()),
        receiver, SLOT(slotName()));

我个人习惯全部用新语法,代码更安全、更清晰。你想想看,如果信号名写错了,旧语法要到运行时才能发现,新语法编译时就报错了,省了多少调试时间。

知识体系结构图

下面这张图帮你理清本章的知识脉络:

Qt概述与环境搭建 Qt简介 Qt Creator安装 第一个Qt项目 信号与槽机制初探 跨平台、模块化、开源 Qt 5 vs Qt 6 选择 在线安装器、组件选择 MinGW vs MSVC 项目文件结构解析 运行第一个窗口 信号(Signal):对象发出的通知 槽(Slot):接收通知并执行的函数 connect():新语法 vs 旧语法

避坑指南

最后分享几个我踩过的坑:

  • 信号与槽连接不生效:检查对象是否被正确创建,connect是否在正确的上下文中调用。我曾经在构造函数里connect了一个还没初始化的指针,结果槽永远不触发。
  • 编译报错找不到Qt头文件:检查.pro文件里的QT += core gui widgets是否写全了。少一个模块就报错。
  • 中文乱码:Qt 6默认用UTF-8,但如果你在Windows下用MSVC编译,源文件编码可能不是UTF-8。建议在.pro文件里加上:QMAKE_CXXFLAGS += -utf-8
  • UI设计器拖拽的控件找不到:记得在构造函数里调用ui->setupUi(this);,否则ui指针是空的。

好了,这一章的内容就到这里。Qt的世界很大,信号与槽只是冰山一角。后面我们会慢慢深入,把Qt的各个模块都玩一遍。记住,多动手写代码,比看十遍书都管用。


公众号:蓝海资料掘金营,微信deep3321