QT connect学习

来源:互联网 发布:长沙黑马程序员地址 编辑:程序博客网 时间:2024/06/06 05:29

前言:信号和槽机制是 Qt 的核心机制,可以让编程人员将互不相关的对象绑定在一起,实现对象之间的通信。

简单的来说,信号和槽都是普通成员函数,当一个对象发出信号,由具有槽的对象接受信号进行响应。

主要方法:connect(sender,SIGNAL(signal), receiver,SLOT(slot));

这里用到了两个宏:SIGNAL() 和SLOT(),根据源码知道这两个宏最后得到const char*类型,就是将普通成员函数进行包装成为类成员函数指针。

sender和receiver则是两个QObject对象指针。

要理解connect的本质需要先弄懂函数指针。

区分不同的函数指针:

void (*FunctionPointer)(); //函数指针
void (ClassName:*MemberFunctionPointer)(); //类成员函数指针

int ClassName::* MemberPointer; //类成员变量指针

 

使用方法:

1.定义一个函数

int func(int x)

{

    return x+1;

}

利用函数指针调用:

 

int(*pf)(int); //定义函数指针

pf = &func;    //指针指向函数,pf=func错误

cout<<(*pf)(5)<<endl; //调用函数,等价于pf(5);

 

利用typedef简化函数指针:

 

typedef int (*pF)(int);

pF y;

y=&abc;

cout<<(*y)(1)<<endl;

 

 

2.定义一个类

class A{

  public:

int x; //成员变量

void func(int); //成员函数

};

 

//外部函数参数为类对象和类成员变量指针

void exfunc(A obj, int A::* p){ //MemberPointer p

cout<<obj.*p<<endl; //使用成员变量

}

void exfunc2(A * obj, int A::* p){

    cout<<obj->*p<<endl; //对象指针应该用->

}

 

template   <class   T>

void exfunc3(T * obj, int T::* p){

    cout<<obj->*p<<endl;

}

 

 

typedef int A::* MemberPointer;

MemberPointer pV;

pV = &A::x ; //成员变量指针的定义,等价于int A::* pV;

A a;

a .* pV=1; //等价于a.x=1;

cout << &a ->* pV << endl; //等价于a.x

exfunc(a,pV); //传入一个对象a,利用对象调用成员变量指针pV

exfunc2(&a,pV); //传入一个对象a的引用,利用对象指针调用成员变量指针pV

exfunc3(&a,pV);

 

3.存在继承关系时使用类成员函数指针

class Person {

    public:

        void sayHello(){

            cout<<"person sayHello   ";

            printf("%d\n",&Person::sayHello); //地址

        }

        virtual void sayName(){ //虚函数

            cout<<"person sayName"<<"  ";

            printf("%d\n",&Person::sayName); //地址

        }

};

 

class Child : public Person {

    public:

    void sayHello(){

        cout<<"child sayHello"<<"  ";

        printf("%d\n",&Child::sayHello);

    }

    virtual void sayName(){

        cout<<"child sayName"<<"  ";

        printf("%d\n",&Child::sayName);

    }

};

 

typedef void (*FunctionPointer)();

typedef void (Person::*PersonMemberFunctionPointer)();

typedef void (Child::*ChildMemberFunctionPointer)();

 

Person someone;

Child xiaoming;

PersonMemberFunctionPointer pp;

pp = &Person::sayHello; //父类成员函数指针

(someone .* pp)(); //调用父类函数

//等价于 (&someone ->* pp)();

//也等价于 someone.sayHello();

(xiaoming.*pp)(); //仍然调用父类函数

//pp=&Child::sayHello;//不能运行,需要强制转换

 

ChildMemberFunctionPointer cp = &Child::sayHello;

(xiaoming.*cp)(); //调用子类重载函数

PersonMemberFunctionPointer pp2 = &Person::sayName;

(someone.*pp2)();

(xiaoming.*pp2)();//必须是公开继承,才有权限

//pp2 = &Child::sayName;//不能运行,需要强制转换

 

熟悉函数指针之后,可以理解connect的本质了。

理解信号:成员函数指针类型的特殊成员变量。

定义两个类和两类成员函数指针:

typedef void (A::*Apointer)();

typedef void (B::*Bpointer)();

 

class A {

  public:

    void (A::*click)(); //A类成员变量的成员函数指针

    void onClicked(){

            cout<<"A的onClick函数!"<<endl;

        }

    B* slotObj; //B类对象的指针

    void TreatClickEvent(){

        (slotObj->*(Bpointer)click)();

    }

};

 

class B {

  public:

    int x=5;

    void onClicked(){

        cout<<"B的onClick函数! 成员变量x的值为"<<x<<endl;

    }

};

 

void runMemberVariblePointer(A * obj, int A::* pMember) {

    cout<<obj->*pMember<<endl;

}

 

void runfuncName(A * obj, void (A::*func)()){

//void (A::*func)()成员函数指针

    (obj->*func)();

}

 

//组合成员变量指针和成员函数指针

void runfuncPointer(A * obj, void (A::*( A::*pfunc ))()){

//void (A::*( A::*pfunc ))(),成员变量指针的成员函数指针,

//等价于Apointer A::* pfunc

 

    (obj->*(obj->*pfunc))();

}

 

//typedef void (A::*Apointer)();

//typedef void (A::*(A::*Signal))();

typedef Apointer A::* Signal;

//简化成员变量指针的成员函数指针,其实就是void (A::*( A::*pfunc ))()

 

//信号是成员变量指针的成员函数指针,槽是成员函数指针

//Apointer slot =void (A::*slot)()

Œ void connect(A* a, Signal signal, Apointer slot){

a->*signal = slot;

//A的成员变量指针的成员函数指针signal指向成员函数指针slot

}

 

 

 void connect(A* a, Signal signal, Bpointer slot){

a->*signal = (Apointer) slot; //需要强制转换

//A的成员变量指针的成员函数指针signal指向B的成员函数指针slot

}

 

Ž void connect(A* a, Signal signal, B* b, Bpointer slot){

    a->*signal = (Apointer) slot;

    a->slotObj = b; //a的成员变量slotObjB类型指针

}

 

 

 

1.连接A本身的信号与槽:

    A a;

runfuncName(&a , &A::onClicked); //调用(a->*onclicked)();

 

//a.click = &A::onClicked

// &A::click = &(A::*click)();

//connectŒ,A的click连接到A的onClicked

connect(&a , &A::click, &A::onClicked);

    (a.*a.click)(); //调用click,发射信号

 

runfuncPointer(&a,&A::click); //调用click,与上相同性质

 

 

2.连接A的信号到B的槽:

B b;

B * fb = &b;

 

//a.click = (void (A::*)())&B::onClicked;

//connect,把A的click连接到B的onClicked

connect(&a, &A::click, &B::onClicked);

    (a.*a.click)(); //调用click,发射信号

 

    //(fb->*(Bpointer)a.click)();

    (b.*(Bpointer)a.click)(); //调用click,需要强制转换

 

 

3.完善连接A的信号到B的槽:

//connectŽ,把A的click连接到B的onClicked

//A的slotObj指向fb,利用fb调用他的onClicked

    connect(&a, &A::click, fb, &B::onClicked);

    a.TreatClickEvent();

    // (fb->*(Bpointer)click)();

将  connect(&a, &A::click, fb, &B::onClicked);

connect(sender,SIGNAL(signal), receiver,SLOT(slot));

对比就可以知道,每个参数的意义。

QT的signal和slot简化了复杂的函数指针,更加方便的进行使用。