qt-signal-tools is a collection of utility classes related to signal and slots in Qt. It includes:
- QtCallback - Package up a receiver and slot arguments into an object for invoking later.
- QtSignalForwarder - Connect signals and events from objects to QtCallback or arbitrary functions.
- QtMetacallAdapter - Low-level interface for calling a function using a list of QGenericArgument() arguments.
- safe_bind() - Create a wrapper around a method call which does nothing and returns a default value if the object is destroyed before the wrapper is called.
- Qt 4.6 (earliest version tested, may also work with older Qt 4.x releases) or Qt 5.x
- The TR1 standard library (for C++03 compilers) or the C++11 standard library (for newer compilers when C++11 support is enabled).
QtCallback is a binder class which provides a way to create callbacks that invoke a signal or slot when invoked, using a mixture of pre-bound arguments and arguments passed to QtCallback::invoke().
Usage:
QtCallback1<int> callback(myWidget, SLOT(someSlot(int,QString)));
callback.bind(42);
// invokes the MyWidget::someSlot() slot with arguments (42, "Hello World")
callback.invoke("Hello World");
void MyWidget::someSlot(int firstArg, const QString& secondArg)
{
}
QtSignalForwarder provides a way to invoke callbacks when an object emits a signal or receives
a particular type of event. The callbacks can be signals and slots
(via QtCallback
) or arbitrary functions using tr1::function
, std::function
, boost::function
or
a similar wrapper.
Qt 5 provides support for connecting signals to arbitrary functions out of the box and to lambdas when using C++11. QtSignalForwarder emulates this for Qt 4.
As well as being able to connect signals to functions that are not slots, this also provides
a way to pass additional arguments to the receiver other than those from the signal using QtCallback::bind()
or std::tr1::bind()
.
Usage:
Connecting a signal to a slot with pre-bound arguments:
MyObject receiver;
QPushButton button;
QtSignalForwarder::connect(&button, SIGNAL(clicked(bool)),
QtCallback(&receiver, SLOT(buttonClicked(int))).bind(42));
// invokes MyObject::buttonClicked() slot with arguments (42)
button.click();
Connecting a signal to an arbitrary function:
using namespace std::tr1;
using namespace std::tr1::placeholders;
SomeObject receiver;
QLineEdit editor;
// function which calls someMethod() with the first-argument fixed (42) and the
// second string argument from the signal
function<void(int,QString)> callback(bind(&SomeObject::someMethod, &receiver, 42, _1));
QtSignalForwarder::connect(&editor, SIGNAL(textChanged(QString)), callback);
// invokes SomeObject::someMethod(42, "Hello World")
editor.setText("Hello World");
For standard signal-slot connections, Qt automatically removes the connection if either the sender or receiver objects are destroyed.
When using QtSignalForwarder::connect(), the connection is automatically removed if the sender
is destroyed. However there is no receiver since the callback is a function
object - which may
call a method on a QObject or it may call a function which is not a QObject method at all.
QtSignalTools provides two solutions to this:
QtSignalForwarder::connect()
accepts an optional context QObject*. The signal will automatically be disconnected if either the sender or the context object is destroyed. This is the approach that should be used if the callback is a method on a QObject. This behaves the same as the context argument toQObject::connect()
in Qt 5.2 and later.- A more generic facility is to use the
safe_bind()
function which creates a wrapper around an object and a method call. The wrapper can then be called with the same arguments as the wrapped method. When a call happens, either the wrapped method is called with the provided arguments, or if the object has been destroyed, nothing happens and a default value is returned. The wrapper created bysafe_bind()
can be used withbind()
andfunction
and can be used together withQtSignalForwarder
to automatically 'disconnect' if the receiver is destroyed.
QScopedPointer<QLabel> label(new QLabel);
// create a wrapper around label->setText() which can be run using
// setTextWrapper(text).
function<void(QString)> setTextWrapper = safe_bind(label.data(), &QLabel::setText);
// create a wrapper around label->text() which either calls label->text() and returns
// the same result or returns an empty string if the label has been destroyed
function<QString()> getTextWrapper = safe_bind(label.data(), &QLabel::text);
setTextWrapper("first update"); // sets the label's text to "first update"
qDebug() << "label text" << getTextWrapper(); // prints "first update"
label.reset(); // destroy the label
setTextWrapper("second update"); // does nothing, as the label has been destroyed
qDebug() << "label text" << getTextWrapper(); // prints an empty string
QtMetacallAdapter is a low-level wrapper around a function or function object (eg. std::function
)
which can be used to invoke the function with a list of QGenericArgument (created by the Q_ARG() macro)
and introspect the function's argument types at runtime.
qt-signal-tools is licensed under the BSD license.
- Qt Signal Adapters - Library for connecting signals to Boost function objects: http://sourceforge.net/projects/qtsignaladapter/
- sigfwd - Library for connecting signals to function objects. Uses Boost. https://bitbucket.org/edd/sigfwd/wiki/Home
- Qt 5 meta-object system changes - http://blog.qt.digia.com/blog/2012/06/22/changes-to-the-meta-object-system-in-qt-5/