Qt编程(3): 信号和槽函数

一、信号和槽核心概念(大白话)

信号和槽是Qt特有的通信机制 ,用来实现对象之间的交互,简单理解就是:一个对象发出信号,另一个对象的槽函数接收并执行动作,全程不用手动调用函数,触发信号就自动运行槽函数,非常适合界面交互、事件响应这类场景。

比如你之前写的按钮点击弹窗,就是按钮发出"被点击"的信号 ,主窗口的槽函数接收到信号后弹出对话框,完全靠信号槽绑定实现自动触发。

核心前提 :使用信号槽的类,必须继承QObject,并且类内第一行加 Q_OBJECT 宏,否则信号槽无法生效,Qt Widgets项目里的主窗口、QDialog、QPushButton都满足这个条件。

二、实用举例:按钮点击弹出对话框(Qt6 完整可运行)

这个例子完全贴合你之前的代码场景,适配当前主流的 Qt6 版本,同时保留你用过的 Qt4 旧版语法(Qt6 依然兼容),重点推荐 Qt5/Qt6 通用的新版函数指针语法,代码可直接复制运行,适配 Qt Widgets 常规项目。

这个例子完全贴合你之前的代码场景,用按钮点击触发槽函数,分别演示Qt4旧版语法(你之前用的)和Qt5+新版语法(更推荐),代码适配Qt Widgets常规项目,直接复制就能用。

场景说明

主窗口放一个按钮,按钮文字设为"弹出子对话框",点击按钮后,触发槽函数,弹出一个简单的模态对话框,全程用信号槽实现交互。

1. 头文件(mainwindow.h)

头文件主要完成类定义、信号槽声明,必须加Q_OBJECT宏,槽函数用private slots声明(旧版要求严格,新版可放宽)。

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>
#include <QDialog>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    // 核心:必须加这个宏,信号槽才能生效
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

// 槽函数声明区,旧版语法必须写在slots关键字下
private slots:
    // 自定义槽函数:点击按钮后执行,弹出对话框
    void showChildDialog();

private:
    Ui::MainWindow *ui;
    // 定义按钮对象(也可以用UI设计师拖拽生成,对应你之前的ui->showChildButton)
    QPushButton *showBtn;
};
#endif // MAINWINDOW_H

2. 源文件(mainwindow.cpp)

源文件完成按钮创建、信号槽绑定、槽函数实现,Qt6 中旧版宏语法可正常运行 ,但强烈推荐新版函数指针写法,编译期检查错误、无运行时失效风险,和你之前的代码完美衔接。

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QLabel>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 设置窗口标题和大小,Qt6 语法无变化
    this->setWindowTitle("Qt6 信号槽示例");
    this->resize(400, 300);

    // 创建按钮,设置文字
    showBtn = new QPushButton("弹出子对话框", this);
    // 把按钮放到窗口中央
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(showBtn);
    QWidget *centerWidget = new QWidget(this);
    centerWidget->setLayout(layout);
    this->setCentralWidget(centerWidget);

    // ===================== Qt6 两种信号槽绑定写法(均兼容) =====================
    // 写法1:你之前用的 Qt4 旧版宏语法(Qt6 兼容,不推荐新项目使用)
    // 缺点:运行时才检查错误,拼写错误不报错,Qt6 官方已不建议新项目使用
    // connect(showBtn, SIGNAL(clicked(bool)), this, SLOT(showChildDialog()));

    // 写法2:Qt5/Qt6 通用新版语法(函数指针,Qt6 首选,编译期强校验)
    // 格式:connect(发送者, &发送者类::信号名, 接收者, &接收者类::槽函数名);
    connect(showBtn, &QPushButton::clicked, this, &MainWindow::showChildDialog);
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 槽函数具体实现:点击按钮后执行的逻辑
void MainWindow::showChildDialog()
{
    // 弹出模态对话框,Qt6 用法不变
    QDialog childDlg(this);
    childDlg.setWindowTitle("子对话框");
    childDlg.resize(300, 200);
    // 对话框加提示文字
    QLabel *tip = new QLabel("这是 Qt6 信号槽触发的弹窗", &childDlg);
    QVBoxLayout *dlgLay = new QVBoxLayout(&childDlg);
    dlgLay->addWidget(tip);

    // 阻塞显示对话框,关闭前无法操作主窗口
    childDlg.exec();
}

3. 主函数(main.cpp)

标准Qt主函数,无需修改,直接运行即可。

cpp 复制代码
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

三、代码逐部分拆解(对应你的旧版connect)

你之前的代码: connect(ui->showChildButton, SIGNAL(clicked(bool)), this, SLOT(showChildDialog()));

  • connect:Qt信号槽绑定函数,负责把信号和槽关联起来

  • ui->showChildButton信号发送者,就是UI里的按钮,负责发出点击信号

  • SIGNAL(clicked(bool))信号,按钮自带的clicked点击信号,bool参数表示按钮是否按下,SIGNAL是Qt4宏,用来包裹信号

  • this信号接收者,当前主窗口,槽函数属于主窗口

  • SLOT(showChildDialog())槽函数,自己定义的函数,信号触发后自动执行这个函数,SLOT是Qt4宏,用来包裹槽函数

四、Qt6 关键注意事项(核心必看)

  1. 参数匹配规则:信号的参数可以比槽函数多,反之不行,比如 clicked 带 bool 参数,槽函数无参数,Qt6 下依然合法;如果槽函数有参数,信号必须有对应类型参数。

  2. Qt6 语法选择(重点) :旧版 SIGNAL/SLOT 宏语法 Qt6 只是兼容,不推荐新项目使用;新版函数指针写法是 Qt6 官方首选,编译期检查错误,彻底避免运行时连接失效,新手优先学这个。

  3. 自定义信号槽:Qt6 中自定义信号槽规则不变,依然需要继承 QObject + Q_OBJECT 宏,信号只需声明无需实现,槽函数正常编写即可。

  4. Qt6 其他小变化:部分旧版弃用接口已移除,但信号槽核心机制、常用控件信号(如 QPushButton::clicked)完全没变,之前学的逻辑直接通用。

  5. 适用场景:界面交互、线程通信、组件间传值等场景,Qt6 依旧靠信号槽实现,是 Qt 核心交互机制,和旧版本用法一致。

  6. 参数匹配规则:信号的参数可以比槽函数多,反之不行,比如clicked带bool参数,槽函数无参数,是合法的;如果槽函数有参数,信号必须有对应参数

  7. 旧版vs新版:旧版语法运行时才会检查错误,拼写错了不报错;新版编译期就检查,更不容易出错,优先用新版

  8. 自定义信号槽:除了Qt自带的信号(按钮点击、窗口关闭),也可以自己定义信号和槽,实现自定义对象通信

  9. 适用场景:界面交互、线程通信、组件间传值等场景都能用,是Qt最核心的交互机制

相关推荐
wwww.wwww2 小时前
qt程序执行时报错:无法定位程序输入点,但是通过IDE的run又可以正常的运行。
开发语言·ide·qt
森G3 小时前
11、交叉编译Opencv----------Opencv移植Arm
qt
乌鸦乌鸦你的小虎牙5 小时前
qt 5.12.8 配置报错(交叉编译环境)
开发语言·数据库·qt
feifeigo1235 小时前
Leslie人口模型MATLAB实现(中长期人口预测)
开发语言·matlab
写代码的二次猿5 小时前
安装openfold(顺利解决版)
开发语言·python·深度学习
一只大袋鼠5 小时前
Redis 安装+基于短信验证码登录功能的完整实现
java·开发语言·数据库·redis·缓存·学习笔记
Anastasiozzzz5 小时前
深入研究Redis的ZSet底层数据结构:从 Ziplist 的级联更新到 Listpack 的完美救场
数据结构·数据库·redis
菠萝蚊鸭5 小时前
x86 平台使用 buildx 基于源码构建 MySQL Wsrep 5.7.44 镜像
数据库·mysql·galera·wsrep
※DX3906※6 小时前
Java排序算法--全面详解面试中涉及的排序
java·开发语言·数据结构·面试·排序算法