用 VS Code 搞 Qt6:让信号和槽自动建立连接

Qt 具备让某个对象的信号与符合要求的槽函数自动建立连接 。弄起来也很简单 , 只要调用这个静态方法即可:
QMetaObject::connectSlotsByName(...);connectSlotsByName 方法需要一个参数,此参数的指针指向一个实例,这个实例自身的信号 , 以及它的子级对象的信号都会自动连接 。
不过,在用的时候要注意以下几点 , 否则 connectSlotsByName 方法是不起作用的 。
1、如果类是从某个 QObject 类派生的 , 比如常见的 QWidget 类,在类的声明中一个定要加上 Q_OBJECT 宏 。这条老周在上一篇中说过,不加这个信号和槽不能建立连接 。
2、对象一定要有 Name,即用 setObjectName 方法设置 。虽然对象可以使用重复的名字,但不建议这样做 , 因为 connectSlotsByName 方法只要找到一个名字匹配的对象,就会停止查找 。所以,就算你设置了 10 个名为“myButton” 的对象,结果也只能有一个会自动绑定信号和槽,其他的同名对象会忽略 。
3、一定要在所有对象都初始化完毕,包括调用 setObjectName 方法设置对象名称后调用 connectSlotsByName 方法 。这样才会有效 。
setObjectName 方法用起来很简单,只要传递对象的名字即可,字符串类型 。名字你可以随便取 。例如
QLabel lb ...lb.setObjectName("bug");这时候,标签对象的名字是“bug” 。
Slot 要支持被自动连接,函数(方法)也是有严格的命名规则的 。你必须按照这个规则来,否则不会被识别 。槽函数命名规则如下:
on_XXX_SSS
1、以“on”开头,每一节用下划线连起来 。
2、XXX 是对象名,注意是对象名,就是用 setObjectName 方法设置的名称,不是你代码中定义的变量名 。这个得注意 , 不能搞错了 。
3、SSS 是信号 。
比如,按钮的 clicked 信号 , 你让要自己写的槽能够被自动连接,就得这样命名槽函数:on_mybtn_clicked 。其中,“mybtn”是对象名 。
------------------------------------------- 银河分隔线 ------------------------------------------
下面咱们来动手做个例子,就好理解了 。
一、先弄好 CMake 文件 。
cmake_minimum_required(VERSION 3.0.0)project(TestApp VERSION 0.1.0)find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED YES)set(CMAKE_AUTOMOC YES)add_executable(TestApp WIN32 main.cpp app.h app.cpp)target_link_libraries(TestApp PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets)这个示例有三个文件 。main.cpp 是写 main 函数的地方 。app.h 和 app.cpp 中是咱们自定义的窗口类——从 QWidget 类派生 。
二、定义 MyWindow 类,基类是 QWidget 。
/** app.h **/#include <QMetaObject>#include <QWidget>#include <QApplication>#include <QObject>#include <QLabel>#include <QPushButton>#include <QMessageBox>#include <QVBoxLayout>#include <QHBoxLayout>class MyWindow : public QWidget{// 这个宏很容易忘了,忘了就不能连接信号和槽了Q_OBJECTpublic:// 构造函数MyWindow(QWidget* parent = nullptr);// 析构函数~MyWindow();private:// 私有函数void initUi(void);// 以下是用到的部件(控件)QPushButton *btn1;QPushButton *btn2;QLabel *lb;// 布局QVBoxLayout *layout;QHBoxLayout *sublayout;// 这几个函数是用于自动绑定的槽private slots:void on_b1_clicked();void on_b2_clicked();};所有 QObject 的子类 , 想使用 Signal 和 Slot ,必须调用 Q_OBJECT 宏 。这里有两个按钮,on_b1_clicked 和 on_b2_clicked 都是槽 。要让两个按钮自动连接 , 必须分别设置它的 object name 为 “b1” 和 “b2” 。
三、下面是 initUi 函数的实现代码,用于初始化窗体 。
void MyWindow::initUi(){// 按钮1btn1 = new QPushButton(this);// 设置按钮1的文本btn1 -> setText("左边");// 重要:给它个名字btn1 -> setObjectName("b1");// 按钮2btn2 = new QPushButton(this);// 设置按钮2的文本btn2 -> setText("右边");// 重要:设置名称btn2 -> setObjectName("b2");// 标签lb = new QLabel("请点击下面的按钮", this);// 布局layout = new QVBoxLayout(this);layout -> addWidget(lb, 0, Qt::AlignTop);sublayout = new QHBoxLayout(this);// 添加要布局的组件sublayout -> addWidget(btn1);sublayout -> addWidget(btn2);layout->addLayout(sublayout);// 窗口this -> setWindowTitle("示例王");this -> resize(240, 100);}调用按钮对象的 setObjectName 方法就可以为其分配名称 。注意在调用 QPushButton 类的构造函数时,要把当前窗口的指针传递给 parent 参数,使用按钮成为 MyWindow 的子级对象 。这样后面才能做信号与槽的自动连接 。
四、在 MyWindow 类构造函数中 , 先调用 initUi,再调用 connectSlotsByName 静态方法 。

推荐阅读