And prone to failure, especially if there is some "hidden" parent inserted by Qt (like a QFrame for example) between some deeply-embedded child and your QMainWindow's status bar.
Ever hear of "signals and slots"? This is a perfect use case. Implement a slot in your MainWindow to receive status bar messages. Connect signals from your child widgets to this slot.
Note that you do not need to expose your MainWindow pointer to every child class that sends these signals. There are a couple of solutions:
1 - Add a signal to each of the classes in between the main window and the child widgets to relay the status update messages. When the main window creates these intermediate it simply connects -their- signal to its update slot. In turn, when each of these intermediate widgets creates its own child widgets, it connects their update signals directly to its update signal. So when a low level widget emits its update signal, it just gets relayed up the chain of signals until it reaches the main window.
2 - Add a singleton QObject-based class to act as the relay class and expose this as an application-level instance (similar to the way QApplication creates the qApp instance). Your main window class connects to this object's status update signal. In turn, every child widget that wants to send updates can connect to the object's status update slot. The object's status update slot simply emits the status update signal with the contents of the message sent to the slot. The drawback to this is that (a) you need a global variable and (b) all status-sending classes need to know how to retrieve it.
Note that for option 1 to work, your intermediate classes also do not need to know if the child classes send status update signals. You can use the QMetaObject system to interrogate the child class to see if it has the signal:
// In the MyMiddleManWidget constructor:
MyChildWidget * pChild = new MyChildWidget( this );
if ( pMeta )
{
// See if it has a "statusUpdate" signal
int sigIndex
= pMeta
->indexOfSignal
( QMetaObject::normalizedSignature( "statusUpdate( QString )" ).
constData() );
if ( sigIndex != -1 )
{
// Yes, it does (index > -1), so connect to it to relay it up the parent-child chain
connect( pChild,
SIGNAL( statusUpdate
( QString ) ),
this,
SIGNAL( statusUpdate
( QString ) ) );
}
}
// In the MyMiddleManWidget constructor:
MyChildWidget * pChild = new MyChildWidget( this );
QMetaObject * pMeta = pChild->metaObject();
if ( pMeta )
{
// See if it has a "statusUpdate" signal
int sigIndex = pMeta->indexOfSignal( QMetaObject::normalizedSignature( "statusUpdate( QString )" ).constData() );
if ( sigIndex != -1 )
{
// Yes, it does (index > -1), so connect to it to relay it up the parent-child chain
connect( pChild, SIGNAL( statusUpdate( QString ) ), this, SIGNAL( statusUpdate( QString ) ) );
}
}
To copy to clipboard, switch view to plain text mode
The only requirement here is that every status update-sending class has to implement the signal with the identical signature. But it allows you to implement this message-passing system using any classes, and it also allows you to add message sending to -any- child widget later simply by implementing the signal in that child widget. When the parent constructs that child, it will automatically link it into the status update system if it checks for the signal. If there are a lot of middle-man widgets created, you could abstract this into a function that does the check and connect:
{
bool bConnected = false;
if ( pParent && pChild )
{
if ( pChildMeta )
{
// See if it has a "statusUpdate" signal
int childSigIndex
= pChildMeta
->indexOfSignal
( QMetaObject::normalizedSignature( "statusUpdate( QString )" ).
constData() );
if ( childSigIndex != -1 )
{
// Yes, it does (index > -1), so now check the parent, too
if ( pParentMeta )
{
int parentSigIndex
= pParentMeta
->indexOfSignal
( QMetaObject::normalizedSignature( "statusUpdate( QString )" ).
constData() );
if ( parentSigIndex != -1 )
{ // Yes!
bConnected
= connect( pChild,
SIGNAL( statusUpdate
( QString ) ), pParent,
SIGNAL( statusUpdate
( QString ) ) );
}
}
}
}
}
bool connectToStatusUpdate( QObject * pParent, QObject * pChild )
{
bool bConnected = false;
if ( pParent && pChild )
{
QMetaObject * pChildMeta = pChild->metaObject();
if ( pChildMeta )
{
// See if it has a "statusUpdate" signal
int childSigIndex = pChildMeta->indexOfSignal( QMetaObject::normalizedSignature( "statusUpdate( QString )" ).constData() );
if ( childSigIndex != -1 )
{
// Yes, it does (index > -1), so now check the parent, too
QMetaObject * pParentMeta = pParent->metaObject();
if ( pParentMeta )
{
int parentSigIndex = pParentMeta->indexOfSignal( QMetaObject::normalizedSignature( "statusUpdate( QString )" ).constData() );
if ( parentSigIndex != -1 )
{ // Yes!
bConnected = connect( pChild, SIGNAL( statusUpdate( QString ) ), pParent, SIGNAL( statusUpdate( QString ) ) );
}
}
}
}
}
To copy to clipboard, switch view to plain text mode
And of course, you could make this even -more- general for connecting -any- signal-passing network by passing the names of the signals / slots you wish to connect as an argument to connectToStatusUpdate():
bool connectSignalChain
( QObject * pParent,
const QString & parentSignalName,
bool bParentSignal,
QObject * pChild,
const QString & childSignalName,
bool bChildSignal
);
bool connectSignalChain( QObject * pParent, const QString & parentSignalName, bool bParentSignal, QObject * pChild, const QString & childSignalName, bool bChildSignal );
To copy to clipboard, switch view to plain text mode
where the "bool bParentSignal" and "bool bChildSignal" are used to decide whether you are connecting signal-to-signal or signal-to-slot. E.g. if bParentSignal and bChildSignal are both true, you use the ( pChild, SIGNAL(), pParent, SIGNAL() ) arguments in the connect. If bParentSignal is true and bChildSignal is false, then you use ( pParent, SIGNAL(), pChild, SLOT() ). If pParentSignal is false, but bChildSignal is true, you connect the opposite way: (pChild, SIGNAL(), pParent, SLOT() ). if both pParentSignal and pChildSignal are false, this is an error - you can't have a slot-slot connection.
You would also have to substitute QMetaObject::indexOfSlot() for QMetaObject::indexOfSignal() depending on the two Booleans.
Have fun. Betcha this was more than you wanted to know on a Saturday morning.
Edit: Or this
You can create a custom QEvent which can be sent from any widget and be catched by you mainwindow.
Bookmarks