Analysis of QT signal and slot mechanism

Source: Internet
Author: User
Tags emit object model requires

Qobject This class is the core of the Qt object model, and most of the QT classes inherit from this category. The central feature of this model is a mechanism called signals and slots (signal and slots) to communicate between objects, you can connect a signal to another slot through the Connect (") method, and you can use the Disconnect (") method to disconnect the connection. You can also temporarily block the signal by calling the Blocksignal (") method.
Qobject organize themselves in the object tree. When you create a qobject and use other objects as the parent object, the object is automatically added to the parent object's
Children () list. The parent object has this object, for example, it will automatically delete all of its child objects in its destructor. You can find an object by using the Findchild () or Findchildren () function.
Each object has an object name (ObjectName ()) and a class name, which can be obtained by the corresponding MetaObject object. You can also use the Inherits () method to determine whether an object's class inherits from another class.
When the object is deleted, it emits a destroyed () signal. You can capture this signal to avoid invalid references to Qobject.
Qobject can receive events through event () and filter events for other objects.     Please refer to Installeventfilter () and EventFilter () for more information. For each object that implements the signal, slot, and attribute, the Q_object macro must be added.

Qobject has implemented so many functions, so how does it work. Let's use its Source Code to solve the secret. There are four implementation files for the Qobject class.


1, Qobject.h

The basic definition of Qobject class is also a header file that we generally define a class.


2, Qobject.cpp

The implementation code for the Qobject class is basically in this file.


3, Qobjectdefs.h

The most important thing in this file is to define the Qmetaobject class, which is the core of the signal, slot, and properties.

4, Qobject_p.h

The code in this file is an auxiliary implementation of the Qobject class, and the most important thing here is to define a Qobjectprivate class to store the Qojbect object's member data.

Understanding this Qobjectprivate class is also the basis for our understanding of QT Kernel source code, which contains data members from every QT object, so let's start with our QT Kern from understanding Qobject's data storage code. El Source Code Tour.

Two: Meta-object Systems (Meta-object system)



Beginning with this section, we explain the functionality of QT Meta-object System and its implementation.

In the process of using QT development, signal and slots are used extensively. For example, in response to a button's Click event, we generally write the following code:

Class Mywindow:public Qwidget { 
  q_object public   
: 
  Mywindow (qwidget* parent): Qwidget (parent)   { 
    qpushbutton* btnstart = new Qpushbutton ("Start", this); 
    Connect (btnstart, SIGNAL (clicked ()), this, SLOT (slotstartclicked ()));   }  
Private slots: 
  void slotstartclicked ();};  

void Mywindow:: slotstartclicked () 
      { 
        //omitted 
       }




In this code, we connect the clicked () signal of the Btnstart button with the slotstartclicked () of the Mywindow, and when the button is clicked by the user, it will send Out a clicked () signal, and then, Mywindow:: slotstartclicked () This slot function is called to respond to the Click event of the button.
This code is the most typical application example of Signal/slot, in the actual work process, Signal/slot also has a more extensive application. To be precise, signal/slot is a technique that QT provides to communicate between objects, so how is this technique implemented in QT?

This is the role of the Meta object System in QT, in order to better understand it, let me first review its function, let us come together to uncover its mysterious veil.



Iii. basic functions of Meta-object System


The Meta Object System is designed based on the following infrastructure:


1, Qobject class
As a base class for every class that needs to take advantage of the meta-object system, the Q_object macro, defined in each class's private data segment, is used to enable meta-object functionality, such as dynamic properties, signals, and slots. The metafile compiler moc (the Meta object complier), MoC parses the C + + source file, if it finds a header file that contains the Q_object macro definition, and then dynamically generates another C + + source file, this new source file contains Q_object implementation code, this new C + + source file will also be compiled and linked to the binary code of this class, as it is also a complete part of this class. Typically, this new C + + source file is preceded by the previous C + + source filename with moc_ as the file name of the new file. The specific process is shown in the following figure:

MOC analysis, you need to judge the source code in the Q_object, Q_property, Q_enums, Q_classinfo, slots, slots, emit and other information, and generate meta-objects, but these keywords most c + + compiler does not know (q_ Except for object), they are all define empty.


The signal slot mechanism of QT is actually to look up the table by name

In addition to providing a mechanism for communicating between objects, the meta-object system also includes the following features:

Qobject::metaobject () method
It gets the meta-object associated with a class

The Qmetaobject::classname () method, which returns the class name of an object during run time, does not require the RTTI (run-time type information) support of the local C + + compiler

Qobject::inherits () method
It is used to determine whether the generation of an object class is inherited from a particular class, which, of course, must be in a direct or indirect derived class of the Qobject class.

Qobject::tr () and Qobject::trutf8 () These two methods translate strings for the internationalization of software


Qobject::setproperty () and Qobject::p Roperty () These two methods dynamically set and get property values based on the property name

In addition to these features, it also uses the Qobject_cast () method to provide dynamic conversions between the Qobject classes, and the Qobject_cast () method functions like the dynamic_cast () of standard C + +, but Qobject_cast () No need for RTTI support,

In a Qobject class or its derived class, we can not define a Q_object macro. If we do not define a Q_object macro in a class, then the corresponding function mentioned here cannot be used in this class, and from Meta-object's point of view, a class that does not define Q_object macro is the same as the ancestor class closest to it, that is to say, The name returned by the Qmetaobject::classname () method is not the name of the class, but the name of the ancestor class closest to it. Therefore, we strongly recommend that any class inherited from Qobject define Q_object macros.


Three: Meta object compiler-Meta Object Compiler (MOC)


Meta-object compiler is used to handle QT C + + extension, MOC analysis C + + source file, if it found in a header file contains Q_object macro definition, and then dynamically generate another C + + source file, this new source file contains Q_object implementation code, This new C + + source file will also be compiled and linked to the binary code of this class, as it is also a complete part of this class.     Typically, this new C + + source file is preceded by the previous C + + source filename with moc_ as the file name of the new file. If you use the Qmake tool to generate the makefile file, all compilation rules that need to use the MOC will be included in the makefile file automatically, so there is no need for the programmer to use the MOC directly


In addition to processing signals and slots, the MOC also handles attribute information, Q_property () macros define property information for classes, and Q_enums () macros define enumerated type lists in a class.     The Q_flags () macro defines the list of flag enumeration types in a class, and the Q_classinfo () macro allows you to insert name/value pairs in the meta information of a class. The files generated by the MOC must be compiled and linked, just like the other C + + file you wrote yourself, otherwise, it will fail during the link.



Code Example:

Class Myclass:public Qobject { 
    q_object 
    Q_property (Priority priority READ priority WRITE SetPriority)     q_ ENUMS (priority) 
    Q_classinfo ("Author", "Oscar Peterson")     q_classinfo ("Status", "Active") public  
: 
    Enum Priority {High, Low, Veryhigh, verylow};
 
    MyClass (Qobject *parent = 0);     Virtual ~myclass ();  
    void SetPriority (priority priority);     Priority priority () const; };


Four: Signal; Slots

Signals and slots are used to communicate between objects, and when a particular event occurs, signal is emit out, and the slot call is used to respond to the corresponding signal.

The QT object already contains many predefined signal, but we can always add a new signal to the derived class.


The QT object already contains many predefined slog, but we can add a new slot in the derived class to handle the signal signal and slot mechanisms we are interested in are type-safe, and signal and slots must match each other (in fact, a Solt parameter can be Fewer parameters than the corresponding signal, because it can ignore extraneous parameters). Signal and slots are loosely paired relationships, emitting signal objects that do not care whether the object is linked to this signal, or how many slots are linked to this signal. The signal and slot mechanism of QT ensures that if a signal and slot are linked, the slots are called at the right time and the correct parameters are used. Both signal and slots can carry any number and type of parameters, and they are all type-safe.


All classes that inherit directly or indirectly from Qobject can contain signals and slots, and when the state of an object changes, the signal can be emit out, which may be of interest to some other object. This object is not concerned with having that object or how many objects are linked to this signal, which is the real message encapsulation, which guarantees that the object can be used as a software component.

Slots are used to receive signals, but at the same time they are also an ordinary class member function, just as an object does not care how many slots are linked to one of its signals, and an object does not care how many signals a slot is linked to. This ensures that the object created with Qt is a real, independent software component.
A signal can be linked to multiple slots, and a slot can also link multiple signals. At the same time, a signal can also be linked to another signal.


All classes that use signals and slots must contain Q_object macros, and this class must derive from the Qobject class (either directly or indirectly), and when a signal is emit out, the slots linked to this signal are immediately invoked. It's like a function call. When this happens, the signal and slot mechanisms have absolutely nothing to do with the GUI's event loop, and after all the slots that link to this signal are executed, the code after the emit code line is executed immediately. When multiple slots are linked to a signal, these slots are executed in a random order, one after the other.


The signal code is generated automatically by the MOC, and the developer must not implement it in its own C + + code, and it will never have a return value. The slot is actually an ordinary class function, and can be called directly, the only special place is that it can be linked with signal.


The C + + preprocessor changes or removes the signal, slot, emit keyword, so, for the C + + compiler, it handles standard C + + source files.


V: Meta Object Class
Earlier we introduced the basic functionality of Meta object, and one of the most important features it supports: Signal & slot basic functionality. Now let's go inside the Meta Object and see how it supports these capabilities.


All data and methods of the Meta Object are encapsulated in a class called Qmetaobject. It is used to query the meta information of a QT class, which contains the following types of meta information:

1. The Signal table (signal table), which has the name of all signal of this corresponding QT class

2. Slot table (slot tables), which has the name of all slots in this corresponding QT class.

3. class Info table, containing the type information of this QT class
4. Property table, which has the name of all the attributes in the corresponding QT class.

5. Pointer to the parent meta object (pointers to parent meta object)



The relationship between the Qmetaobject object and the QT class:

Each Qmetaobject object contains the meta-information of a QT class corresponding to it


Each QT class (Qobject and its derived classes) has a static (static) Qmetaobject object associated with it (note: the definition of class must have a Q_object macro, otherwise there is no meta object)


Each Qmetaobject object holds a pointer to the Qmetaobject object of the parent class of the QT class that corresponds to it. Or, we can say, "Every Qmetaobject object holds a pointer to its father." Note: Strictly speaking, this statement is not correct, at least it is not rigorous.




Q_OBJECT macro



The function of Meta Object is realized, this macro has made great contribution. First, let's take a look at how this macro is defined:

#define Q_OBJECT \ Public
: \
    static const qmetaobject staticmetaobject; \
    Virtual Const qmetaobject * MetaObject () const; \
    virtual void *qt_metacast (const char *); \
    virtual int qt_metacall (qmetaobject::call, int, void * *); \
    qt_t R_functions \
private: \
    static void Qt_static_metacall (Qobject *, qmetaobject::call, int, void * *); \
    struct Qprivatesignal {}; \


Here, we first ignore the two macros, Q_object_check and qt_tr_functions.

We see that a static type of class variable staticmetaobject is defined first, and then there is a method MetaObject () that gets the pointer to the object. The most important thing here is the definition of class variable staticmetaobject. This means that all Qobject objects will share this staticmetaobject class variable, and it will do all the functions of the signal and slot, so we need to take a closer look at what's going on.
VI: Qmetaobject class data members
Let's take a look at the definition of qmetaobject, and we'll first examine the member data contained in the Qmetaobject object.

    
struct Q_core_export qmetaobject
{
   //...

.... ..... struct {//private data
        const qmetaobject *superdata;
        Const Qbytearraydata *stringdata;
        const UINT *data;
        typedef void (*staticmetacallfunction) (Qobject *, qmetaobject::call, int, void * *);
        Staticmetacallfunction Static_metacall;
        Const QMETAOBJECT * Const *relatedmetaobjects;
        void *extradata; Reserved for future use
    } D;


}


The code above is all the data members defined by the Qmetaobject class. It is these members who record so much information about all signal,slot,property,class information. Let's explain these member variables individually:
Const Qmetaobject *superdata:
This variable points to the parent class of the corresponding Qobject class, or to the Qmetaobject object of the ancestor class. How to understand this sentence. We know that each Qmetaobject object must have a corresponding Qobject class (or a subclass derived directly or indirectly), note: Here is the class, not the object.

Then each Qobject class (or its derived class) may have a parent class, or the parent class of the parent class, or many ancestor classes before the inheritance hierarchy. or no parent class (Qobject). So superdata this variable is the Qmetaobject object that points to the closest ancestor class. For the Qobject class Qmetaobject object, this is a null pointer, because Qobject does not have a parent class.



Let's take a few examples to illustrate:

Class Animal:public Qobject  
{  
   q_object  
  //... 
};   
.. Class Cat:public Animal   
{  
     q_object  
    //......  
}  

So, cat::staticmetaobject.d.superdata, this pointer variable points to an object that is Animal::staticmetaobject,

The Animal::staticmetaobject.d.superdata pointer variable points to an object that is Qobject::staticmetaobject

Qobject::staticmetaobject.d.superdat the value of this pointer variable is NULL



But if we change the definition of the above class to the following definition, it will be different:

Class Animal:public Qobject 
{
///Q_object, this class does not define this  
//... 
}; 
Class Cat:public Animal  
{   q_object   
//...... 
}
So, cat::staticmetaobject.d.superdata, this pointer variable points to an object that is qobject::staticmetaobject because animal::staticmetaobject this object does not exist.


const char *stringdata:


As the name implies, this is a pointer to string data. But it is quite different from the usual string pointers we use, and the string pointers we use are just pointers to a string, and this pointer points to a number of strings. So it's not a string array. Haha, it's not. Because a C + + string array requires each string in the array to have the same length, it is possible to make an array. So it's not a string pointer array. No, that's what it is. Let's take a look at its specific value, or let's take the example of Qobject, the class Qmetaobject, to illustrate it.


The following is an array of strings pointed to by the Qobject::staticmetaobject.d.stringdata pointer, in fact, it points to a contiguous memory area, and this contiguous memory area holds a number of strings.


static const char qt_meta_stringdata_qobject[] =
{

"qobject\0\0destroyed (qobject*) \0destroyed ()"
" Deletelater () \0_q_reregistertimers (void*) qobject* "
" Qstring\0objectname\0parent\0qobject () "
" Qobject () "
};

What is this string all about? There is, Class name, Signal name, Slot name, property name. See how familiar these people are, right, they are the most core feature attributes supported by meta system.


Since they are all unequal strings, how does QT index these strings so that they can be found correctly when needed? The third member has officially appeared.

const UINT *data;


This pointer essentially refers to an array of positive integers, except that the length of the array in the different object varies, depending on how many signal,slot,property are defined in the corresponding class.
The value of this array of integers, in part, indicates the index value of the different strings in the previous variable (stringdata), but one thing to note here is that the value in this is not a direct indication of the index value of each string, and this value needs to be computed by a corresponding algorithm. To get the correct index value for the string.


The following is the value of the array of positive integers that the qobject::staticmetaobject.d.data pointer points to.

static const uint qt_meta_data_qobject[] =   {   content:   2,        // revision 0,       //  ClassName 0,    0, // classinfo 4,   12, // methods 1,    32, // properties 0,    0, // enums/sets 2,    35, // constructors  //signals: signature, parameters, type,  tag, flags 9,    8,    8,    8,  0x05, 29,    8,    8,    8, 0x25,  / / slots: signature, parameters, type, tag, flags   41,     8,    8,    8, 0x0a, 55,    8,     8,    8, 0x08, // properties: name, type,  flags   90,   82, 0x0a095103,// constructors: signature,  parameters, type, tag, flags   108,  101,    8,     8, 0x0e,  126,    8,    8,  
   8, 0X2E, 0        // eod


In a nutshell, the first section, the integer value of the//content area, is the same in every Qmetaobject entity object, and the meaning is the same, but the exact value is different. A struct specifically defines the section, meaning it is clearly stated in the comments above.


struct qmetaobjectprivate
{
    int revision;
    int className;
    int Classinfocount, classinfodata;
    int Methodcount, methoddata;
    int Propertycount, propertydata;
    int Enumeratorcount, enumeratordata;
    int Constructorcount, Constructordata;  Since revision 2
    int flags;//since Revision 3
    int signalcount;//since Revision 4
    //Revision 5 introduces  Changes in normalized signatures, no new Members
    //revision 6 added Qt_static_metacall as a member of each Q_object And inside Qmetaobject itself
};


This struct is defined as the first Secton, and the above numerical comparison, very clear, right.


The second section, which begins with//signals. The value in this section indicates that the Qobject class contains two signal,
The third section, which begins with//slots. The value in this section indicates that the Qobject class contains two slots.
The fourth section, which begins with//properties. The value in this section indicates that the Qobject class contains a property definition.
The fifth section, which begins with//constructors, indicates that the class of Qobject has two constructor.



const void *extradata;


This is a pointer to the QMETAOBJECTEXTRADATA data structure, about which the pointer is skipped first.

For each specific integer value and the Entity data pointed to the corresponding algorithm, it is a bit troublesome, here does not explain the details, interested friends to go

Read the source code, there must be a lot of discoveries.




Seven: Connect, the story behind the scenes


As we all know, connecting a signal with a slot requires the use of the Qobject class's Connect method, which functions as an object signal and

Another object slot is connected to achieve the purpose of communication between objects. What the Connect has done behind the scenes. Why emit a signal after the

The corresponding slot will be called. All right, let's solve the puzzle one after the other.

SIGNAL and SLOT macro definitions
When we call the Connect method, we usually write this:
Obj.connect (&obj, SIGNAL (Destroyed ()), &app, SLOT (ABOUTQT ()));
We see that the names of signal and slots are contained in two uppercase signal and slots, and what are these two? Original Signal and Slots

is a QT-defined two macro. Well, let's see what these two macros have done, and here are the definitions of the two macros:


# define SLOT (a) "1" #a #

#define SIGNAL (a) "2" #a
The original QT signal and slot are converted to a string, and also in the front of the string with additional symbols, signal front added ' 2 ', the slot is preceded by ' 1 '. So

Yes, we wrote the following connect call in front of the compiler after preprocessing,

Handy: Obj.connect (&obj, "2destroyed ()", &app, "1aboutQt ()"));



When the Connect function is called, it checks whether the two parameters are correctly converted using the two macros, which is based on the two predecessors.

is equal to 1 or 2, if not, the Connect function will of course fail.


It then checks to see if the object that sent the signal has this signal, by finding the object's class corresponding to the Staticmetaobject object contained in the
The string that D.stringdata points to contains the name of the signal, which, during this check, uses the string of integers that d.data points to, through which

Value to calculate the starting address of each specific string. Similarly, the same method is used to check the slot to see if the object in response to the signal contains a corresponding slot.

If any of the two checks fails, the Connect function fails and returns FALSE.
The previous steps are doing the necessary checks, and the next step is to associate the object that sent the signal with the object that responds to signal.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.