PDA

View Full Version : How to "hook" to existing signal?



QPlace
8th September 2009, 18:49
I would like to connect to a widget's signal. When signal is emitted I need to do some processing and then envoke the orignal slot to which this signal was connected in the first place.

So, if the widget is a button I have a wrapper like the one below. My questions are in the comments. And the general question - is that approach correct at all? May be there is something else already provided by Qt?


class objBtnHook
{
public:
objBtnHook (QAbstractButton* btn)
{
// how to store connected slot that is currently connected to the "clicked" signal?

QObject::disconnect (btn, SIGNAL(clicked()),0,0);
QObject::connect(btn, SIGNAL(clicked()), this, SLOT(hookedclicked()) );
}
private slots:
void hookedclicked()
{
// do some processing

// invoke original slot - how? with QMetaObject::invokeMethod?
}
}

drhex
8th September 2009, 22:13
Is it important to you that your slot is called before the "original" slot is?
Otherwise you can simply connect clicked() to your slot and both slots will be executed (in arbitrary order)

QPlace
8th September 2009, 22:16
Yes, it is the core of the problem. "My" slot should be called first in order to do validation. The idea behind that requirement is that every user action (click on the button) should be validated relative to the currently running threads.

nish
9th September 2009, 02:37
may be this is little newbie approach but here it is..
do not disconnect anything.
use a bool global flag which will become true at the end of hooked function.
check for that flag to become true in a event loop upon the entry of the original slot
make that flag false again at the end of original slot.
:)

drhex
9th September 2009, 08:46
A wild & crazy idea: yank the original button out of the layout and replace it with your own copy of it. The clicked signal of the copied button is connected to your slot, and the last thing that slot does is to "emit chain()", where the chain-signal is connected to the clicked-signal of the original button...

wysota
9th September 2009, 13:03
In your situation, is it possible that more than one slot is connected to the signal you want to intercept?

QPlace
9th September 2009, 13:44
No, in my case each button has only one "original" slot connected to it.

Let me explain what the underlying issue is - may be there is a solution that Qt supports in "out-of-the-box" manner.

I have a dialog with several tabs on it. Each tab hosts a widget of different kind. Each tab widget represents a view into a separate thread. These threads are separated from each other in terms of implementation, they are connected only by application logic (synchronization mutexes). These views, i.e widgets, have this in common - they all have several buttons that control their respective threads and also provide the user with ability to view underlying thread-specific data.

So, what I am trying to do is to have a "action synchronizer" instance in each of the widgets. This synchronizer is intialized with all widget buttons that user can click on. When user clicks one of these buttons the synchronizer inspects the state of threads and makes a decision if this click is currently allowed or not.

This is generic functionality, I don' have to repeat it in every slot. So, I am creating synchronizer instance and populate it with all widget buttons. Now I have to "hook up" to the current signal-slot connection of the button. And - oops! - I don't see the way to do it.

wysota
9th September 2009, 16:39
No, in my case each button has only one "original" slot connected to it.
So maybe it shouldn't be a signal-slot connection in the first place? Maybe you should use events or something?


So, what I am trying to do is to have a "action synchronizer" instance in each of the widgets. This synchronizer is intialized with all widget buttons that user can click on. When user clicks one of these buttons the synchronizer inspects the state of threads and makes a decision if this click is currently allowed or not.

This is generic functionality, I don' have to repeat it in every slot. So, I am creating synchronizer instance and populate it with all widget buttons. Now I have to "hook up" to the current signal-slot connection of the button. And - oops! - I don't see the way to do it.

So why don't you connect the clicked() signal of each of the buttons to a slot in your synchronizer class and emit some signal from the slot if it is allowed, or don't emit it if it is not? Then you can connect your true functionality to that signal(s) and act accordingly.

QPlace
9th September 2009, 17:43
Thank you, the second option that you suggested is a possibility.

The important thing that I am taking out of this discussion is that there is no easy way to "hook" into existing "signal-slot" connection.

wysota
9th September 2009, 19:10
Actually there is, but that's only a "peek-only" solution, you can't modify anything.

QPlace
9th September 2009, 22:55
Would you mind to show how to peek into the signal-slot connection?

Originally I wanted to store existing slot somewhere, but soon realized that it will be like storing pointer-to-member function without the actual instance, which I believe is impossible.

May it is possible, using Qt, to peek into signal-slot connection and store it somewhere for later restoration? (dreaming :) )

wysota
10th September 2009, 08:01
Would you mind to show how to peek into the signal-slot connection?
QSignalSpy.


May it is possible, using Qt, to peek into signal-slot connection and store it somewhere for later restoration? (dreaming :) )
If you subclass the object, you can provide your own implementation of qt_metacall() and there you can do whatever you want. But of course that's not possible for already instantiated objects of already existing classes.

I still think you are trying to implement a wrong approach here.