Signal and slot
Signals and slots are used for communication between objects. The signal/slot mechanism is a central feature of QT and may be the most different part of QT and other toolkit.
In graphic user interface programming, we often want to notify another widget of a change. Generally, we want any class of objects to communicate with other objects. For example, if we are parsing an XML file, when we encounter a new tag, we may want to notify the list view that we are used to express the structure of the XML file.
Older toolkit uses a communication method called callback to achieve the same purpose. Callback refers to a function pointer. If you want a processing function to notify you of some events, you can pass the pointer of another function (callback) to the processing function. The processing function calls the callback when appropriate. Callback has two main drawbacks. First, they are not type-safe. We are never sure that the handler uses the correct parameters to call the callback. Second, the callback and handler functions are strongly associated, because the handler must know which callback to call.
A summary of some signal and slot connections
In QT, we have a technology that can replace callback. We use signals and slots. When a specific event occurs, a signal is sent. Qt windows have many predefined signals, but we can always add our own signals by inheritance. A slot is a function that can be called to process specific signals. Qt has many predefined window components, but the usual habit is that you can add your own slots so that you can process the signals you are interested in.
The signal and slot mechanism are type-safe: the signature of a signal must match the signature of its receiving slot. (In fact, the signature of a slot can be less than the signature of the signal it receives, because it can ignore the additional signature .) Because the signatures are consistent, the compiler can help us detect Type mismatch. Signals and slots are loosely linked: a class that emits signals does not need to know or pay attention to which slot needs to receive the signal. The QT signal and slot mechanism can ensure that if you connect a signal to a slot, the slot will be called using the signal parameters at the correct time. Signal and slot can use any number or type of parameters. They are completely type-safe: there will be no more core dump callbacks ).
All classes inherited from the qobject class or one of its sub-classes (such as the qwidget class) can contain signals and slots. When objects change their States, signals are sent. In a sense, they may be interested in the outside world. This is what all objects do during communication. It does not know or care whether there is anything to receive the signal it sends. This is the true information encapsulation and ensures that the object can be used as a software component.
An example of signal and slot connection
Slots can be used to receive signals, but they are normal member functions. A slot does not know whether it is connected by any signal. In addition, the object does not know about this communication mechanism and can be used as a real software component.
You can connect many signals to a single slot you want, And one signal can also be connected to many slots you want. It is also possible to directly connect one signal to another. (When the first signal is sent, the second signal is immediately sent .)
In general, signals and slots constitute a powerful component programming mechanism.
A small example
A minimum C ++ class declaration is as follows:
Class foo
{
Public:
Foo ();
Int value () const {return val ;}
Void setvalue (INT );
PRIVATE:
Int val;
};
A small QT class is as follows:
Class FOO: Public qobject
{
Q_object
Public:
Foo ();
Int value () const {return val ;}
Public slots:
Void setvalue (INT );
Signals:
Void valuechanged (INT );
PRIVATE:
Int val;
};
This class has the same internal status as the public method for access, but it also supports programming using signal and slot components: This class can transmit a signal, valuechanged (), to tell the outside world that its status has changed, and it has a slot. Other objects can send signals to this slot.
All classes that contain signals and/or slots must mention q_object in their declaration.
It can be implemented by the application writer. Here is a possible implementation of FOO: setvalue:
Void FOO: setvalue (int v)
{
If (V! = Val ){
Val = V;
Emit valuechanged (v );
}
}
Emit valuechanged (v) transmits the valuechanged signal from the object. As you can see, you can use emit signal (arguments) to transmit signals.
The following is a method for connecting two objects:
Foo A, B;
Connect (& A, signal (valuechanged (INT), & B, slot (setvalue (INT )));
B. setvalue (11); // A = undefined B = 11
A. setvalue (79); // A = 79 B = 79
B. Value ();
Call. setvalue (79) will send a valuechanged () signal, and B will receive this signal in its setvalue () slot, that is, B. setvalue (79) is called. Next, B will transmit the same valuechanged () signal, but because there is no slot connected to B's valuechanged () signal, nothing happens (the signal disappears ).
Note that only when V! When it is set to Val, The setvalue () function sets this value and transmits signals. This avoids endless loops in the case of loop connections (such as B. valuechanged () and A. setvalue.
This example shows that objects can work together without knowing each other, as long as a connection is established between them at the beginning.
The Preprocessing Program changes or removes the signals, slots, and emit keywords so that the standard C ++ compiler can be used.
Run MOC on a class with defined signals and slots. This will generate a C ++ source file that can be compiled and connected with other object files to reference the program.
Signal
When the internal state of an object changes, the signal is sent. In some ways, it may be interesting for the object proxy or owner. Only the class that defines a signal and its subclass can transmit this signal.
For example, a list box emits both highlighted () and activated () signals. Most objects may only be interested in the activated () signal, but sometimes they want to know which entries in the list box are highlighted currently. If two different classes are interested in the same signal, you can connect the signal to the two objects.
When a signal is transmitted, the connected slot is immediately executed, just like a normal function call. The signal/slot mechanism does not depend on the event loop of any graphical user interface. After all the slots are returned, emit will also return.
If several slots are connected to a signal, when the signal is sent, these slots are executed one by one in any order.
The signal is automatically generated by MOC and must not be implemented in the. cpp file. They cannot have any return type (for example, void ).
Pay attention to parameters. Our experience shows that if the signal and slot do not use special types, they can be used multiple times. If qscrollbar: valuechanged () uses a special type, such as hypothetical qrangecontrol: range, it can only be connected to a slot designed to process qrangecontrol. Simple programs that are the same as Part 1 of tutorial 1 will be impossible.
Slot
When a signal connected to the slot is sent, this operation is called. Slots are common C ++ functions and can be called like them. Their only feature is that they can be connected by signals. The Slot Parameter cannot contain the default value, and is the same as the signal. It is unwise to use a specific type for slot parameters.
Because the slot is a common member function, there is something very interesting about it. They have the same access permissions as common member functions. The access permission of a slot determines who can connect to it:
A public slots: A zone contains a slot where any signal can be connected. This is very useful for component programming: You have generated many objects that do not know each other and connect their signals and slots so that information can be correctly transmitted, and like a railway model, open it and let it run.
A protected slots: The slots that can be connected only after the signal of this class and its subclass is included. This means that these slots are only part of the implementation of the class, rather than its external interfaces.
A private slots: contains the slots that can be connected by signals of the class itself. This means that it is very closely related to this class, and even its sub-classes do not have the trust of connection rights.
You can also define a slot as virtual, which is also very useful in practice.
The signal and slot mechanism is very effective, but it is not as fast as the "real" callback. The signal and slot are a little slow because of the flexibility they provide, although these differences can be ignored in practical applications. Generally, transmitting a signal connected to the slot is about 10 times slower than directly calling the non-virtual function call receiver. This is the overhead required to locate the connection object. You can safely repeat all the connections (for example, check whether the concurrent receiver is damaged during the launch) and arrange any parameters in the general way. When ten non-virtual function calls sound a lot, for example, the time overhead is only less than any "new" or "delete" operation. When you perform a string, vector, or list operation, you need to "new" or
"Delete", the signal and slot are only responsible for a very small part of the time overhead of a complete function call location. No matter when you use a system call in a single slot or call more than 10 functions indirectly, the time is the same. On a i585-500 machine, you can transmit about 2,000,000 signals per second to one receiver, or send about 1,200,000 signals to two receivers. The simplicity and flexibility of the signal and slot mechanism is very worthwhile for time overhead, and your users may not even notice it.
Metadata
The metadatabase Compiler (MOC) parses the class declaration in a C ++ file and generates the C ++ code for initializing the metadatabase. The meta object includes the names of all signals, slots, and pointers to these functions. (For more information, see why QT does not use a template to implement signals and slots ?)
The meta object includes some additional information, such as the class name of the object. You can also check whether an object inherits a specific class, for example:
If (widget-> inherits ("qbutton ")){
// Yes. It is a push button, radio button, or another button.
}
A real example
This is a simple example that has been commented out (the code snippet is selected from qlcdnumber. h ).
# Include "qframe. H"
# Include "qbitarray. H"
Class qlcdnumber: Public qframe
Qlcdnumber inherits the qobject that contains the vast majority of signal/slot knowledge through the related declarations such as qframe and qwidget and # include.
{
Q_object
Q_object is a member function implemented by MOC by the pre-processor. If you get a number of compiler error messages such as "virtual function qbutton: classname not defined, you may forget to run MOC or include the MOC output in the connection command.
Public:
Qlcdnumber (qwidget * parent = 0, const char * name = 0 );
Qlcdnumber (uint numdigits, qwidget * parent = 0, const char * name = 0 );
It is not directly related to MOC, But if you inherit the qwidget, you certainly want to obtain the parent and name parameters in your constructor, and pass them to the constructor of the parent class.
Some parsers and member functions are omitted here, and MoC ignores these member functions.
Signals:
Void overflow ();
When the qlcdnumber is requested to display a non-energy value, it sends a signal.
If you do not pay attention to overflow, or you think it will not happen, you can ignore the overflow () signal, that is, you can not connect it to any slot.
On the other hand, if you want to call two different error functions when the number overflows, you can easily connect the signal to two different slots. Qt will call both of them (in any order ).
Public slots:
Void display (INT num );
Void display (double num );
Void display (const char * Str );
Void sethexmode ();
Void setdecmode ();
Void setoctmode ();
Void setbinmode ();
Void smalldecimalpoint (bool );
A slot is a receiving function used to obtain information about the status changes or changes of other widgets. Use qlcdnumber to set the displayed number, just like the code above. Because display () is an interface for this class and other parts of the program, this slot is public.
Several routines connect the newvalue signal of the qscrollbar to the display slot, so the LCD number can continue to display the value of the scroll bar.
Note that the display () is overloaded. When you connect a signal to the slot, QT selects the appropriate version. If callback is used, you will find five different names and track the types by yourself.
Some irrelevant member functions have been omitted from the example.
};