Signals and Slots
Signals and slots are used for communication between objects. The signal/slot mechanism is a central feature of QT and may be the most distinct part of QT and other toolkits.
In graphical user interface programming, we often expect a change in one widget to be notified to another window widget. More generally, we want objects of any kind to be able to communicate with other objects. For example, if we are parsing an XML file, and when we encounter a new label, we may want to notify the list view that we are using to express the structure of the XML file.
Older toolkits use a means of communication called callbacks to achieve the same purpose. A callback is a pointer to a function, so if you want a handler to notify you of events, you can pass the pointer of another function (callback) to the handler function. The handler function invokes the callback at the appropriate time. The callback has two main drawbacks. First of all, they are not type-safe. We have never been able to determine that the handler function invokes the callback using the correct arguments. Second, the callback and handler functions are strongly linked, because the handler must know which callback to invoke.
A summary diagram of some signal and slot connections
In QT we have a technique that can replace callbacks. We use signals and slots. When a particular event occurs, a signal is emitted. QT's widgets have a lot of predefined signals, but we can always add our own signals by inheriting them. A slot is a function that can be invoked to handle a particular signal. QT's Window widget is also a lot of predefined slots, but the usual habit is that you can add your own slots so that you can handle the signals you're interested in.
The mechanism of the signal and groove is type safe: the signature of a signal must match the signature of its receiving slot. (In fact, a slot can have less signatures than the signal it receives because it ignores additional signatures.) Because the signatures are consistent, the compiler can help us detect type mismatches. Signals and slots are loosely linked: a class that emits signals does not have to know or notice which slot to receive this signal. The mechanism of the QT signal and slot ensures that if you connect a signal to a slot, the slot is invoked at the correct time using the parameter of the signal. Signals and slots can use any number, any type of parameter. They are completely type-safe: There will be no callback core dumps.
All classes that inherit from the Qobject class or one of its subclasses (such as the Qwidget Class) can contain signals and slots. When objects change their state, the signals are sent, and in a sense they may be interested in the outside world. That's what all the objects do when they communicate. It does not know or notice whether there is anything to receive the signal it emits. This is the true message encapsulation and ensures that the object can be used as a software component.
Example of a 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 a lot of signals to the single groove you want, and a signal can be connected to many of the slots you expect. It is also possible to connect a signal directly to another signal. (At this point, the second signal is fired as soon as the first signal is launched.) )
In general, signals and slots constitute a powerful component programming mechanism.
a small example
A minimal 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 state, and the public method to access the state, but it also supports programming using signal and slot components: This class can send a signal, valuechanged (), to tell the outside world its state has changed, and it has a slot, Other objects can send signals to this slot.
All classes that contain signals and/or slots must refer to Q_object in their declarations.
Slots can be implemented by the creator of the application. Here is a possible implementation of Foo::setvalue ():
void Foo::setvalue (int v)
{
if (v!= Val) {
val = v;
Emit valuechanged (v);
}
}
The line emit valuechanged (v) emits valuechanged signals from the object. As you can see, you emit signals by using emit signal (arguments).
Here's a way to connect two objects together:
Foo A, B;
Connect (&a, SIGNAL (valuechanged (int)), &b, SLOT (int));
B.setvalue (11); A = = = undefined b =
A.setvalue (+);//A = = = =
b.value ();
Calling A.setvalue (79) causes A to emit a valuechanged () signal, and B will receive the signal in its setValue () slot, which is called B.setvalue (79). Then b emits the same valuechanged () signal, but nothing happens (the signal disappears) because no slots are connected to the valuechanged () signal of B.
Note that the SetValue () function only sets this value and emits a signal only when V!= Val. This avoids the case of endless loops in the case of a circular connection (such as b.valuechanged () and A.setvalue () connected).
This example shows that objects can work together without knowing each other, as long as the connection is established between them at the initial time.
The preprocessor changes or removes the signals, slots, and emit keywords so that you can use the standard C + + compiler.
Run MOC on a class that defines a signal and slot. This generates a C + + source file that can be compiled and connected to a reference program with other object files.
Signal
When the internal state of an object changes, the signal is emitted, and in some ways it may be interesting for the object agent or the owner. Only a class that defines a signal and its subclasses can emit this signal.
For example, a list box emits both highlighted () and activated () signals. Most objects may be interested only in activated (), but sometimes you want to know which item in the list box is highlighted at the moment. If two different classes are interested in the same signal, you can connect the signal to the two objects.
When a signal is emitted, the slot it is connected to will be executed immediately, just like a normal function call. The signal/slot mechanism is completely independent of any graphical user interface event loop. When all the slots are returned, emit will also return.
If several slots are connected to a signal, when the signal is emitted, the slots are executed one after another in any order.
The signal is automatically generated by MOC and must not be implemented in the. cpp file. Nor can they have any return type (for example, using void).
You need to be aware of the parameters. Our experience shows that if the signals and slots 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 slots designed to handle Qrangecontrol. Simple and Tutorial 1 of the 5th part of the same program will be impossible.
Trough
This is called when a signal connected to the slot is launched. Slots are also normal C + + functions and can be called like them; their only feature is that they can be connected by signals. The parameters of a slot cannot contain a default value and, like a signal, it is unwise to use your own particular type for slot parameters.
Because slots are ordinary member functions, there is something very interesting about them, as well as having access to normal member functions. The access rights of a slot determine who can connect to it:
A public slots: The zone contains a slot in which any signal can be connected. This is useful for component programming: you generate objects that are not known to each other, connect their signals and slots so that information can be transmitted correctly and, like a railroad model, open and let it run.
A protected slots: The zone contains the slots after which a signal of this class and its subclasses can be connected. This means that these slots are only part of the implementation of the class, not its interface with the outside world.
A private slots: The district contains a slot in which the signal of the class itself can be connected. This means that it is very close to this class, and even its subclasses do not have the trust of connecting rights.
You can also define a slot as virtual, which is also useful in practice.
The mechanism of signals and slots is very effective, but it is not as fast as a "real" callback. Signals and slots are slightly slower because of the flexibility they provide, although these differences can be ignored in practical applications. Typically, sending a signal to and from a slot is about 10 times times slower than a receiver directly calling those that are not virtual function calls. This is the overhead required to locate a connection object, and it is safe to repeat all connections (for example, to check whether a concurrent receiver is corrupted during launch) and to arrange any parameters in a normal manner. When 10 non-virtual function calls sound a lot, for example, the time overhead is only a little less than any "new" or "delete" operation. When you perform a string, vector, or list operation, you need "new" or "delete", and the signal and slot are responsible for only a very small part of the time overhead of a full function call. Whenever you use a system call in a slot and indirectly invoke more than 10 functions, the time is the same. On a i585-500 machine, you can send 2,000,000 or so signals per second to connect to a receiver, or 1,200,000 or so to connect to two receivers. The simplicity and flexibility of signal and slot mechanisms are well worth the cost of time, and your users are not even aware of it.
Meta Object Information
The Meta Object Compiler (MOC) resolves a class declaration in a C + + file and generates the C + + code for initializing the Meta object. The Meta object includes the names of all signal and slot functions, as well as pointers to these functions. (For more information, see why QT does not use templates to achieve signals and slots.) )
The Meta object includes some additional information, such as the object's class name. You can also check whether an object inherits a particular class, such as:
if (Widget->inherits ("Qbutton")) {
//Yes, it is a push button, Radio button, or other button.
}
a real example.
This is a simple annotated example (the code snippet is selected from Qlcdnumber.h).
#include "qframe.h"
#include "qbitarray.h"
class Qlcdnumber:public Qframe
Qlcdnumber the Qobject that contains most of the signal/slot knowledge through Qframe and qwidget, and #include declarations.
{
Q_object
Q_object is a member function that the preprocessor expands to declare several MOC implementations, and if you get compiler error messages such as "virtual function qbutton::classname not defined", you Xu forgot to run MoC or forget to include 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 Qwidget, you certainly want to get both 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 Qlcdnumber is requested to display an impossible value, it emits a signal.
If you are not aware of the overflow, or you think the overflow will not occur, you can ignore the overflow () signal, which means you can not connect it to any slot.
If, on the other hand, you want to call two different error functions when the number overflows, you can simply connect the signal to two different slots. QT will be called both (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 receive function that is used to obtain information about the state of other widgets. Qlcdnumber use it, just like the code above, to set the number displayed. Because display () is an interface to the rest of the class and program, the slot is public.
Several routines connect the Qscrollbar newvalue signal to the display slot, so the LCD number continues to display the scroll bar value.
Note that display () is overloaded, and QT will select the appropriate version when you connect a signal to this slot. If you use a callback, you will find five different names and track the type yourself.
Some unrelated member functions have been omitted from the example.
};