The principle of QT signal and groove realization

Source: Internet
Author: User
Tags class definition function definition

Some netizens complain:

Which Daniel can help me, explain the underlying implementation of the signal slot mechanism.
do not have that source of analysis, as long as the clear talk is how to send signals, how to choose the appropriate slot, and then react. Which is similar to the corresponding flow of a signal slot ... Solution Ah ...

This article uses ISO C + + step-by-step implementation of an extremely simplified signal and slot system (the entire program 4 files a total of 121 lines of code). Hope to help the C + + users who have just entered the QT world to understand how QT's core signal slot and Meta object system works.

Another: You may be interested in the text from C + + to Qt

dbzhang800 2011.04.30

Note: The QT5 staging Warehouse has introduced a new kind of signal and slot syntax: signals can be connected to ordinary functions, ordinary member functions of classes, lambda functions (rather than signal functions and slot functions), as described in the new syntax for signals and slots (QT5) dbzhang800 2011.06.15 qt signal and Groove

GUI program, when we click a button, we expect a function of our custom to be invoked. In this respect, the older toolset (toolkits) is implemented through a callback function (callback), and the magic of QT is that it replaces the callback with the technology of the signal (signal) and slot (slot).

Before we go on, let's take a look at the most common connnect functions:

Connect (BTN, "2clicked ()", This, "1onBtnClicked ()")

You may feel a little bit Kentson, because for the sake of clarity, I do not directly use the familiar signal and slot two macros, the macro definition is as follows:

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

When the program is running, connect with two strings, you can set up the signal and Groove Association, then, it is if it does. C + + experience can tell us: the class should be stored in the signal and slot string information string and signal slot functions to be associated

And this, is through the magic of the Meta object System (QT object system preprocessor called MOC, the file preprocessing after the generation of a moc_xxx.cpp file, and then a compilation of other files).

Next, we may try to use pure C + + to implement their own meta object system (we need to have a preprocessor, in this article with both hands to replace, the preprocessing generated file is Db_xxx.cpp).

Before we proceed, we can take a look at our final class definition

[CPP]   View plain copy class object     {         DB_OBJECT   public:         object ();          virtual ~object ();          static void db_connect (object *, const char *, object *,  const char *);         void testsignal ();      db_signals:         void sig1 ();      public db_slots:         void slot1 ();      friend class metaobject;     private:          ConnectionMap connections;    };     

introducing the Meta Object System

To define your own signals and slots to distinguish them from ordinary members (so that the preprocessor can know how to extract the information), we need to create some "keyword" db_signals db_slots

Class object
{public
:
    object ();
    Virtual ~object ();
Db_signals:
    void Sig1 ();
Public db_slots:
    void slot1 ();
By using its own preprocessor, extract the information and place it in a separate file (such as db_object.cpp): The rule is simple, extracting the name of the signal and slot and putting it into the string. can have multiple signals or slots, in order "sig1/nsig2/n"
static const char sig_names[] = "sig1/n";
static const char slts_names[] = "slot1/n";
How can the information of these signals and slots be associated with the class, and how is it accessed?

We can define a class that holds information:

struct MetaObject
{
    const char * sig_names;
    const char * slts_names;
};

And then as a static member of object ( Note Oh, this is our Meta object ):

Class Object
{
    static metaobject meta;
...

As a result, our preprocessor can generate such db_object.cpp files:

#include "object.h"

static const char sig_names[] = "sig1/n";
static const char slts_names[] = "slot1/n";
MetaObject Object::meta = {sig_names, slts_names};

Information extraction problem solved: However, there is a serious problem, we define the keyword C + + compiler do not know Ah, how to do.

Oh, good to do, by defining the macro, the problem is not resolved:

# define Db_slots
# define Db_signals protected
establish a signal slot link

Our ultimate goal: when the signal is triggered, can find and trigger the corresponding slot. So with the information of the signal and the slot, we can establish the connection between the signal and the slot. We save the signal and slot correspondence to a mutlimap by Db_connect:

struct Connection
{
    Object * receiver;
    int method;
};

Class Object
{public
:
...
    static void Db_connect (object*, const char*, object*, const char*);
...
Private:
    std::multimap<int, connection> connections;

There should be no explanation on the above, so let's just see what db_connect should say:

void Object::d b_connect (object* sender, const char* SIG, object* receiver, const char* SLT)
{
    int sig_idx = find_s Tring (Sender->meta.sig_names, SIG);
    int slt_idx = find_string (Receiver->meta.slts_names, SLT);
    if (Sig_idx = = 1 | | slt_idx = = 1) {
        perror ("signal or slot not found!");
    } else {
        Connection c = {receiver, SLT_IDX};
        Sender->connections.insert (std::p air<int, Connection> (Sig_idx, C));
    }

First, we look for the existence of the name of the signal and slot from the Meta object information, and if it exists, the index of the signal and the information of the receiver are stored in a map of the sender of the signal. If the signal or slot is invalid, nothing is done.

Here we define a find_string function, which is a simple string lookup (not listed here). activation of the signal

With the connection information, let's see how the signal was sent.

In Qt, we all know to use emit to send signals:

Class Object
{public
:
    void Testsignal () ...
};

void Object::testsignal ()
{
    db_emit sig1 ();
}

Here db_emit is a god horse thing. C + + compiler does not know Ah, it does not matter, look carefully, add a line on the line

#define Db_emit

As I can see from the previous object definition, the so-called signals or slots are just ordinary C + + class member functions. Since it's a member function, you need a function definition: slot function: Because it contains the functional code we need, we all think of defining it in the Object.cpp file, there's no problem. Signal function: Its function body does not need to write itself. So, where is it? This is the content of this section.

The signal function is generated by our "preprocessor", that is, it is defined in our Db_object.cpp file:

void Object::sig1 ()
{
    metaobject::active (this, 0);
}

When we preprocess the source file, we know it's the first few signals. So the slot that is associated with it is called according to its index. The specific work was given to the MetaObject class:

Class Object;
struct MetaObject
{
    const char * sig_names;
    const char * slts_names;

    static void Active (Object * sender, int idx);

How to write this function: The idea is very simple from the previous save connected map, find the object and slot associated with the signal call the object this slot

typedef std::multimap<int, connection> Connectionmap;
typedef std::multimap<int, Connection>::iterator Connectionmapit;

void Metaobject::active (object* sender, int idx)
{
    connectionmapit it;
    std::p air<connectionmapit, connectionmapit> ret;
    ret = Sender->connections.equal_range (idx);
    for (It=ret.first It!=ret.second; ++it) {
        Connection c = (*it). Second;
        C.receiver->metacall (C.method);
    }

Addendum: call to slot

This last key question is how the slot function is invoked based on an index value. Call slot functions directly we all know that a normal function can now be invoked through the index, so we have to define an interface function

Class Object
{
    void metacall (int idx);
...

How the function is implemented. This goes back to our Meta object preprocessing process, because in the preprocessing process, we can associate the slot's index with the call to the slot.

So, in preprocessing generated files (db_object.cpp), we can easily generate their definitions:

void Object::metacall (int idx)
{
    switch (IDX) {case
        0:
            slot1 ();
            break;
        Default: Break
            ;}
    ;
}

To this point, we have implemented a simplified signal and slot program for ourselves. Here we look at all the code for the program: the family photo class definition file object.h [CPP]   View plain copy #ifndef  db_ object   #define  DB_OBJECT   #include  <map>   # define db _slots   # define db_signals protected   # define db_emit    class object;   struct metaobject   {        const char * sig_names;       const char * slts_ names;       static void active (object * sender, int &NBSP;IDX);  };   struct connection   {  

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.