二.信号-槽(C++实战:QT代码解读)

内容参考于《Qt Creator快速入门》(第三版)
目的:使用c++,不是为了深入学习c++也不是为了学习QT

二.信号-槽

1. 基本示例

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

mydialog.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

namespace Ui {
class MyWidget;
}

class MyWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MyWidget(QWidget *parent = 0);
    ~MyWidget();

private:
    Ui::MyWidget *ui;

// 声明this中的槽(可以直接理解为处理函数handler)
public slots:
    void showChildDialog();

};

#endif // MYWIDGET_H

mydialog.c

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDialog>

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);

    // 创建一个信号(showChildButton的clicked信号)-槽(this的showChildDialog槽)
    connect(ui->showChildButton, &QPushButton::clicked,
            this, &MyWidget::showChildDialog);
}

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

void MyWidget::showChildDialog()
{
    // 弹出一个对话框
    QDialog *dialog = new QDialog(this);
    // 模态对话框(不处理就无法操作其他)
    dialog->setModal(true);
    dialog->show();
}

自动生成的ui_mywidget.h

/********************************************************************************
** Form generated from reading UI file 'mywidget.ui'
**
** Created by: Qt User Interface Compiler version 5.12.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_MYWIDGET_H
#define UI_MYWIDGET_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_MyWidget
{
public:
    QPushButton *showChildButton;
    QLabel *label;

    void setupUi(QWidget *MyWidget)
    {
        if (MyWidget->objectName().isEmpty())
            MyWidget->setObjectName(QString::fromUtf8("MyWidget"));
        MyWidget->resize(400, 300);

        // 按钮控件
        showChildButton = new QPushButton(MyWidget);
        showChildButton->setObjectName(QString::fromUtf8("showChildButton"));
        showChildButton->setGeometry(QRect(150, 210, 75, 23));
        label = new QLabel(MyWidget);
        label->setObjectName(QString::fromUtf8("label"));
        label->setGeometry(QRect(80, 80, 141, 41));

        retranslateUi(MyWidget);

        QMetaObject::connectSlotsByName(MyWidget);
    } // setupUi

    void retranslateUi(QWidget *MyWidget)
    {
        MyWidget->setWindowTitle(QApplication::translate("MyWidget", "MyWidget", nullptr));
        showChildButton->setText(QApplication::translate("MyWidget", "\346\230\276\347\244\272\345\255\220\347\252\227\345\217\243", nullptr));
        label->setText(QApplication::translate("MyWidget", "\346\210\221\346\230\257\344\270\273\347\225\214\351\235\242\357\274\201", nullptr));
    } // retranslateUi

};

namespace Ui {
    class MyWidget: public Ui_MyWidget {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_MYWIDGET_H

2. 原理

参考文章

class Demo : public QObject
{
	Q_OBJECT

public:
	Demo();
	int value() const { return val; }public slots:
	void setValue(int);

signals:
	void valueChanged(int);

private:
	int val;
};
// 由样例可看到,类的定义中有两个关键字slots和signals,还有一个宏Q_OBJECT。
// 在Qt的程序中如果使用了信号与反应槽就必须在类的定义中声明这个宏,
// 不过如果你声明了该宏但在程序中并没有信号与反应槽,对程序也不会有任何影响,
// 所以建议大家在用Qt写程序时不妨都把这个宏加上。使用slots定义的就是信号的功能实现,即反应槽,例如:

void Demo::setValue(int v)
{
	if (v != val)
	{
		val = v;
		emit valueChanged(v);
	}
}

// 这段程序表明当setValue执行时它将释放出valueChanged这个信号。
// 以下程序示范了不同对象间信号与反应槽的连接。
Demo a, b;
connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
b.setValue(11);
a.setValue(79);
b.value(); // b的值将是79而不是原先设的11

// 在以上程序中,一旦信号与反应槽连接,当执行a.setValue(79)时就会释放出一个valueChanged(int)的信号,
// 对象b将会收到这个信号并触发setValue(int)这个函数。当b在执行setValue(int)这个函数时,
// 它也将释放valueChanged(int)这个信号,当然b的信号无人接收,因此就什么也没干。

由于在样例中使用了Qt特有的关键字,必须用Qt的中间编译工具moc.exe把该段代码转换为无专用关键字的C++代码才能为这些编译程序所解析、编译与链接。
连接信号和槽:

connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)

发出信号:

emit f(param);
3. 通过函数名自动关联

on_showChildButton_clicked 由on+对象+信号名组成。这种机制的实现基本是通过.ui文件自动生成,前提条件不限止于依赖于setObjectName指定对象名。

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

namespace Ui {
class MyWidget;
}

class MyWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MyWidget(QWidget *parent = 0);
    ~MyWidget();

private:
    Ui::MyWidget *ui;

public slots:
    void on_showChildButton_clicked();

};

#endif // MYWIDGET_H

mywidget.c

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDialog>

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);
}

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

void MyWidget::on_showChildButton_clicked()
{
    QDialog *dialog = new QDialog(this);
    dialog->setModal(true);
    dialog->show();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值