Written by Bo Thorsen
2016/03/01
Sometimes you have to stop a class from emitting a signal for a while. One example that just came up on the Qt interest list was an application that modifies a file which it also monitors with a QFileSystemWatcher. You usually don’t want a fileChanged signal when the modification comes from your own application.
The solution is quite standard and have been published in other blogs as well. But all of those I’ve seen miss one or two features. Which is quite a lot for a class this small. And this is also a cute little test for some nice Qt code, so I thought I’d publish my own version of this class.
The basic idea is simple, you want to have an object that controls blocking signals. So the code you write will be something like this:
{
SignalBlocker blocker(targetObject);
targetObject->doSomethingThatEmitsASignal();
}
Sometimes people ask: Why not just do the following?
targetObject->blockSignals(true);
targetObject->doSomethingThatEmitsASignal();
targetObject->blockSignals(false);
There are three problems with this. The first problem is that the signals might already be blocked, and this code will unblock them. This is one of the problems most SignalBlocker implementations I’ve seen miss.
The second problem is that doSomethingThatEmitsASignal() might throw an exception. If this happens, the signals will stay blocked. But with an object, the destructor will be called even in the case of an exception.
Finally, the doSomethingThatEmitsASignal() could end with delete this, so the code doing the unblocking must handle the case where the target object has been deleted. QPointer is the right solution for this, since it listens to the destroyed() signal. And no, that is never blocked. This problem is also not caught by the SignalBlocker implementations I’ve seen.
The full SignalBlocker implementation should be something like this:
/**
* Small helper class that blocks all signals from an object for the lifetime of this object.
* it is safe against deletion of the object before deletion of this.
*
* This class was written by Bo Thorsen of Viking Software .
* The code is in the public domain.
*/
class SignalBlocker {
public:
explicit SignalBlocker(QObject* object) : mObject(object) {
mWasBlocked = object->signalsBlocked();
object->blockSignals(true);
}
~SignalBlocker() {
if (mObject && !mWasBlocked)
mObject->blockSignals(false);
}
private:
// Disabled
SignalBlocker(const SignalBlocker&);
SignalBlocker& operator=(const SignalBlocker&);
QPointer mObject;
bool mWasBlocked;
};