[QT in the implementation principle of signal and groove mechanism.]
[Tan.zhenhua]
One: [Each object] has a corresponding record of the object of the object.
Class on the primary object:
QMetaObject class:
/ ****************************************** /
// class name
Const char * const class_name,
// Parent class name
QMetaObject * superclass,
// Record SLOT information
Const Qmetadata * const slot_data,
// number of records
INT N_SLOTS,
// Record Signal Information
Const Qmetadata * const signal_data,
// number of records
INT N_SIGNALS
/ ******************************************************************************************************************** ** /
INT Numslots (Bool Super = false) const; // Number of returns
INT NumSignals (Bool Super = false) const; // Returns the number of signals
INT FINDSLOT (Const Char *, Bool Super = false) const; // lookup slot
INT FINDSIGNAL (const char *, bool super = false) const; // lookup signal
/ / Return the slot of the specified position
Const Qmetadata * Slot (int index, bool super = false) const;
/ / Return the signal of the specified location
Const Qmetadata * Signal (int index, bool super = false) const;
// list of all slots names
Qstrlist slotnames (Bool Super = false) const;
// list of all signal names
Qstrlist SignalNames (Bool Super = False) Const;
// Slot start index
Int slotoffset () const;
// Signal start index
Int signaloffset () const;
/ ****************************************************************************************************** /
Static QmetaObject * MetaObject (const char * class_name);
Static Bool HasmetaObject (const char * class_name);
QMetadata class:
// Record meta-object data for signal and groove
Struct Qmetadata
{
Const char * name; // Name
const QUMETHOD * METHOD; / / Detailed Description Information
Enum access {private};
Access Access; // Access Permissions
}
Second: [QObject class implements signal and slot mechanism]
It uses the information record of the meta-object record to realize the signal and slot mechanism.
(1) Realization of signal and slot establishment connection
Interface function:
//connection
// Parameter (send object, signal, receiving object, signal / groove)
Static Bool Connect (Const Qobject * Sender, Const Char * Signal,
Const Qobject * Receiver, const char * member); BOOL Connect (const Qobject * sender, const char * signal,
Const char * member) const;
Static Bool Disconnect (const Qobject * sender, const char * signal,
Const Qobject * Receiver, const char * member;
Bool disconnect (const char * signal = 0,
Const Qobject * Receiver = 0, const char * member = 0);
Bool disconnect (const Qobject * receiver, const char * member = 0);
/ / Internal implementation
/ / (Send object, index, receiving object, type of processing signal, index of processing signal signal / groove)
Static Void Connectinternal (Const Qobject * Sender, int signal_index,
Const Qobject * Receiver, int event_index;
Static Bool Disconnectinternal (const Qobject * sender, int signal_index,
Const Qobject * Receiver, int event_index;
The principle of signaling and groove connection:
1 stage
Bool Qobject :: Connect (const QObject * sender, // send object
Const char * signal, // signal
Const Qobject * Receiver, // Receive object
Const char * member // slot
)
{
/ / Check the send object, signal, receive object, and the slot is not NULL
IF (sender == 0 || Receiver == 0 || signal == 0 || MEMBER == 0) {
Return False;
}
/ / Get the meta object of the send object
QmetaObject * smeta = sender-> metaObject ();
// check the signal
IF (! Check_Signal_Macro (Sender, Signal, "Connect", "Bind"))
Return False;
// Get the index of the signal
INT signal_index = Smeta-> FindSignal (Signal, True);
IF (Signal_index <0) {// Normalize and Retry
NW_SIGNAL = Qt_rmws (Signal-1); // Remove Whitespace
Signal = nw_signal.data () 1; // Skip MEMBER TYPE CODE
Signal_index = Smeta-> FindSignal (Signal, True);
}
// If the signal does not exist, exit
IF (Signal_index <0) {// No Such Signal
Return False;
}
/ / Get a metadata object of the signal
Const Qmetadata * SM = SMETA-> SIGNAL (Signal_INDEX, TRUE); // Get the signal name
Signal = SM-> Name;
/ / Get the type of processing signal (is the signal / slot)
INT MEMBCODE = MEMBER [0] - '0'; // Get Member Code
// Send a signal object
QObject * s = (QObject *) sender; // We need to change them
// Receive signal objects
QObject * r = (QObject *) received; // internally
/ / Get the meta-object that receives the object
QmetaObject * Rmeta = r-> metaobject ();
INT member_index = -1;
Switch (MEMBCODE) {// Get Receiver MEMBER
Case Qslot_code: // If it is a slot
// Get the slot index
MEMBER_INDEX = RMETA-> FINDSLOT (MEMBER, TRUE);
IF (MEMBER_INDEX <0) {// Normalize and Retry
NW_MEMBER = qt_rmws (member); // Remove Whitespace
MEMBER = NW_MEMBER;
MEMBER_INDEX = RMETA-> FINDSLOT (MEMBER, TRUE);
}
Break;
CASE Qsignal_code: // If it is a signal
// Get signal index
MEMBER_INDEX = RMeta-> FindSignal (Member, true);
IF (MEMBER_INDEX <0) {// Normalize and Retry
NW_MEMBER = qt_rmws (member); // Remove Whitespace
MEMBER = NW_MEMBER;
MEMBER_INDEX = RMeta-> FindSignal (Member, true);
}
Break;
}
/ Exit if there is no corresponding signal or slot,
IF (MEMBER_INDEX <0) {
Return False;
}
/ / Check the connected parameters (send signals, receiving the object, the slot or signal of the signal)
IF (! S-> Checkconnectargs (Signal, Receiver, MEMBER) {
Return False;
} else {
/ / Get the metadata object of the processing signal
Const Qmetadata * RM = MEMBCODE == Qslot_code?
RMeta-> slot (Member_index, true):
Rmeta-> Signal (Member_index, true);
IF (rm) {
//establish connection
/ / (Send the object, the index of the signal, the object of the received signal,
Treatment signal type, index of processing signals)
Connectinternal (Sender, Signal_index, Receiver, MEMBCODE, MEMBER_INDEX);
}
}
Return True;
}
2 stage
//establish connection
/ / (Send signal object, index of the signal, the object of the received signal, the type of processing signal, the index of the processing signal) VOID QOBJECT :: Connectinternal (const Qobject * sender, int signal_index,
Const Qobject * Receiver,
INT MEMBCODE, INT MEMBER_INDEX)
{
// Send a signal object
QObject * s = (QObject *) Sender;
// Receive the object of the signal
QObject * r = (QObject *) Receiver;
// If the connection query table of the send object is NULL, it is established.
IF (! S-> Connections) {// CREATE CONNECTIONOKUP TABLE
S-> Connections = New Qsignalvec (Signal_Index 1);
Q_Check_ptr (S-> Connections);
S-> Connections-> setAutodelete (true);
}
/ / Get a list of connection to the corresponding signal of the object
QCONNECTIONLIST * CLIST = S-> Connections-> At (Signal_index);
IF (! CLIST) {// CREATE Receiver List
Clist = new qConnectionList;
Q_Check_ptr (CLIST);
CLIST-> SetAutodelete (TRUE);
S-> Connections-> INSERT (Signal_Index, Clist);
}
QmetaObject * Rmeta = r-> metaobject ();
Const Qmetadata * RM = 0;
Switch (MEMBCODE) {// Get Receiver MEMBER
Case Qslot_code:
RM = RMeta-> slot (MEMBER_INDEX, TRUE);
Break;
Case Qsignal_code:
RM = RMeta-> Signal (Member_index, True);
Break;
}
//establish connection
QCONNECTION * C = New QCONNECTION (R, MEMBER_INDEX, RM? RM-> Name:
"qt_invoke", membcode);
Q_Check_PTR (c);
/ / Add the connection to the list of connected objects
CLIST-> APPEND (C);
/ / Deconed whether the list of send objects of the received object is NULL
IF (! r-> senderobjects) // CREATE LIST OF SENDERS
{
/ / Establish a list of send objects for receiving objects
R-> senderObjects = new qsenderObjectList;
}
/ / Add the send object to the list of send objects
R-> senderObjects-> append (s); // add sender to list
}
(2) Operation functions activated when the signal occurs
interface:
/ ************************************************** *************
** Method for activating Slot
*********************************************************** ************** / VOID Qobject :: Activate_Signal (int signal)
{
#ifndef qt_no_preliminary_signal_spy
IF (qt_preliminary_signal_spy) {
/ / The signal is not blocked
// signal> = 0
/ / The connection list is not empty, or the corresponding connection of the signal exists.
IF (! SignalsBlocked () && signal> = 0 &&
(! CONNECTIONS ||! Connections-> At (signal))) {
//
QuObject O [1];
Qt_SPY_SIGNAL (this, signal, o);
Return;
}
}
#ENDIF
IF (! connect || SignalsBlocked () || Signal <0)
Return;
// Get the list of connections corresponding to the signal
QCONNECTIONLIST * CLIST = Connections-> At (Signal);
IF (! cred)
Return;
QuObject O [1];
//
Activate_signal (Clist, O);
}
/ ************************************************** *************
** Method for activating Slot
*********************************************************** ************* /
Void Qobject :: Activate_Signal (QConnectionList * Clist, QuObject * O)
{
IF (! cred)
Return;
#ifndef qt_no_preliminary_signal_spy
IF (qt_preliminary_signal_spy)
Qt_SPY_SIGNAL (this, connections-> findref (clist), o);
#ENDIF
QObject * Object;
// Send a list of objects
QSenderObjectList * SOL;
// Old send object
QObject * oldsender = 0;
//connection
QCONNECTION * C;
IF (clist-> count () == 1) {// save iterator
// Get a connection
C = clist-> first ();
//
Object = C-> Object ();
// Get a list of send objects
Sol = Object-> senderObjects;
IF (SOL) {
/ / Get old send objects
Old Shender = SOL-> CurrentSender;
//
Sol-> Ref ();
/ / Set new send object
Sol-> CurrentSender = THIS;
}
IF (c-> membertype () == qsignal_code) // If it is a signal, send it out
Object-> qt_emit (C-> Member (), O);
Else
Object-> qt_invoke (C-> Member (), O); // If it is a slot, execute
//
IF (SOL) {
// Set the recovery to the old send object
Sol-> CurrentSender = Old Shender;
IF (Sol-> Deref ())
DELETE SOL;
}
} else {
QCONNECTION * CD = 0;
QConnectionListit it (* clist);
While ((c = it.current ())) {
IT;
IF (c == CD)
CONTINUE;
CD = C;
Object = C-> Object ();
// Set the current send object before operation
Sol = Object-> senderObjects;
IF (SOL) {
Old Shender = SOL-> CurrentSender;
Sol-> Ref ();
Sol-> CurrentSender = THIS;
}
// If it is a signal, send it out.
IF (c-> membertype () == qsignal_code) {
Object-> qt_emit (C-> Member (), O);
}
// If it is a slot, execute
Else {
Object-> qt_invoke (C-> Member (), O);
}
// Restore the current send object after operation
IF (SOL) {
Sol-> CurrentSender = Old Shender;
IF (Sol-> Deref ())
DELETE SOL;
}
}
}
}