3

用 VS Code 搞 Qt6:让信号和槽自动建立连接 - 东邪独孤

 1 year ago
source link: https://www.cnblogs.com/tcjiaan/p/16860878.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

用 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_OBJECT

public:
    // 构造函数
    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()
{
    // 按钮1
    btn1 = new QPushButton(this);
    // 设置按钮1的文本
    btn1 -> setText("左边");
    // 重要:给它个名字
    btn1 -> setObjectName("b1");

    // 按钮2
    btn2 = 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 静态方法。

MyWindow::MyWindow(QWidget *parent)
    : QWidget::QWidget(parent)
{
    // 调用以下函数,初始化UI
    initUi();
    // 一定要在所有东东都初始化完毕后调用才有效
    QMetaObject::connectSlotsByName(this);
}

五、下面是两个槽函数的实现。功能简单,用 QMessageBox 显示弹出框。

void MyWindow::on_b1_clicked()
{
    QMessageBox::information(this, "好消息", "左转是男厕", QMessageBox::Ok);
}
void MyWindow::on_b2_clicked()
{
    QMessageBox::information(this, "好消息", "右转是女厕", QMessageBox::Ok);
}

六、在 main.cpp 中写 main 函数。

#include "app.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    // 实例化窗口
    MyWindow wind;
    // 显示窗口
    wind.show();
    // 消息循环
    return app.exec();
}

运行结果如下面超清动画所示。

367389-20221106122006180-738215357.gif

从结果可以看到,名为“b1”的按钮自动将 clicked 信号连接到 on_b1_clicked 函数;名为“b2”的按钮自动将 clicked 信号连接到 on_b2_clicked 函数。

好了,今天的主题咱们就聊到这儿了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK