Qt自定义信号和槽函数

一、背景

实际开发中,如果仅使用 Qt 提供的信号函数和槽函数,会经常遇到信号函数的参数类型和个数无法满足实际需求、信号函数和槽函数的参数类型不匹配等问题。解决此类问题,最简单有效的方式就是:自定义场景需要的信号函数和槽函数

二、自定义信号函数

信号函数指的是符合以下条件的函数:

  • 定义在某个类中,该类直接或间接继承自 QObject 类;
  • 用 signals 关键字修饰;
  • 函数只需要声明,不需要实现;
  • 函数的返回值类型必须为 void,而参数的类型和个数可以不限。

举个例子

class MyWidget:public QWidget{
    //Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
    Q_OBJECT
//自定义信号函数
signals:
    void MySignal(QString mess);
public:
    void emitSignal(){
        emit MySignal(message);
    }
private:
    QString message;
};

我们为 MyWidget 类新增了一个 emitSignal() 方法和一个 message 属性,emitSignal() 方法中的emit MySignal(message);语句就表示发射 MySignal 信号。当程序中执行 emitSingal() 函数时,就会发出 MySignal 信号,message 属性的值也会随信号一同发出,对应的槽函数可以接收到 message 的值。 

三、自定义槽函数

Qt5 中,槽函数既可以是普通的全局函数、也可以是类的成员函数、静态成员函数、友元函数、虚函数,还可以用 lambda 表达式表示。
和信号函数不同,槽函数必须手动定义(实现)。槽函数可以在程序中直接调用,但主要用来响应某个信号。自定义一个槽函数时,需要注意以下几点:

  • 槽函数的返回值必须和信号函数相同,由于信号函数的返回值一定是 void,所以槽函数的返回值也必须为 void;
  • 对于带参的信号函数,槽函数可以选择接收所有参数,则参数的类型、顺序、个数都必须与信号函数相同;也可以选择接收前几个参数,这些参数的类型、顺序都必须与信号函数相同;还可以选择不接受任何参数。
  • 槽函数的参数个数只能比信号函数少,不能比信号函数多;
  • 槽函数的参数不能有默认值。
class MyWidget:public QWidget{
    //Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
    Q_OBJECT
signals:
    void MySignal(QString mess1,QString mess2);
public:
    void emitSignal(){
        emit MySignal(message1,message2);
    }
    //类的成员函数
    void recSlot1(QString mess){
        qDebug() << "执行 recSlot1() 成员函数,输出" << mess;
    }
//指明定义的是槽函数
public slots:
    void recSlot2(QString mess1,QString mess2){
        qDebug() << "执行 recSlot2() 槽函数,输出"<< mess1 << " " << mess2;
    }
public:
    QString message1;
    QString message2;
};
//全局函数
void recSlot3(){
    qDebug() << "执行 recSlot3() 全局函数";
}

程序中,重点关注 recSlot1()、recSlot2()、recSlot3() 这 3 个函数:

  • recSlot1() 是 MyWidget 类内部的 public 成员函数,可以当做槽函数使用;
  • recSlot2() 位于 MyWidget 类的内部,修饰它的关键字是 public slots。slots 和 emit 一样,是 Qt 扩展的一个关键字,专门用来修饰槽函数。也就是说,recSlot2() 是 MyWidget 类中的槽函数。
  • recSlot3() 是全局函数,可以当做槽函数使用。

四、 关联

一旦确定了信号接收者和槽函数,当 MySignal 信号发出后,与之相连的槽函数就会执行。那么,程序中如何发出 MySignal 信号呢?

对于 MySignal() 信号函数,程序中不会直接调用它,而是借助 connect() 连接某个槽函数,实现的语法格式是:

    MyWidget myWidget;
    QObject::connect(&myWidget,&MyWidget::MySignal,信号接收者,槽函数);

五、实例

    //main.cpp
    #include 
    #include 
    #include 
    class MyWidget:public QWidget{
        //Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
        Q_OBJECT
    //信号函数
    signals:
        void MySignal(QString mess1,QString mess2);
    public:
        //发射信号的函数
        void emitSignal(){
            emit MySignal(message1,message2);
        }
        //普通类成员函数
        void recSlot1(QString mess){
            qDebug() << "recSlot1()" << mess;
        }
    //槽函数
    public slots:
        void recSlot2(QString mess1,QString mess2){
            qDebug() << "recSlot2()"<< mess1 << " " << mess2;
        }
    public:
        QString message1;
        QString message2;
    };
    //全局函数
    void recSlot3(){
        qDebug() << "recSlot3()";
    }
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //创建主窗口
        MyWidget mywidget;
        mywidget.message1 = "test signal";
        mywidget.message2 = "tset this is case";
        //类的成员函数作为槽函数
        QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot1);
        //信号函数和槽函数相连接
        QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot2);
        //全局函数作为槽函数
        QObject::connect(&mywidget,&MyWidget::MySignal,&recSlot3);
        mywidget.show();
        //发射 Signal 信号
        mywidget.emitSignal();
        return a.exec();
    }
    //MyWidget类的定义应该放到 .h 文件中,本例中将其写到 main.cpp 中,程序最后需要添加 #include "当前源文件名.moc" 语句,否则无法通过编译。
    #include "main.moc"

执行程序,会弹出一个 myWidget 空白窗口,同时输出以下信息: 

Qt自定义信号和槽函数_第1张图片

 参考:

Qt自定义信号和槽函数

你可能感兴趣的:(Qt,qt,开发语言,c++)