Kind of RAII to manage GUI state in Qt
I would like to know if you think it is reasonable to use a pattern similar to RAII to manage GUI state in Qt. By GUI state I mean the following: I've some widgets (including the mouse cursor state) I want to go (not) visible/enabled/changed after I leave some method, and I don't want to put everything I do in a giant try catch in this way:
widget1->show();
...
widgetN->show();
try {
...
}
catch(...) {
widget1->hide();
...
widgetN->hide();
throw;
}
widget1->hide();
...
widgetN->h开发者_如何学编程ide();
If I create an object that allows me to associate the hide/setEnabled/setCursor function (maybe a boost functor) on its constructor and that calls this associated function on its destructor (provided that all exceptions this function can throw are eaten/lost in the destructor) I can have a much cleaner code. Is this reasonable? what I'm not seeing?
Any comment/suggestion will be really welcomed.
Thanks in advance,
Federico
It's completely reasonable. The technique you're after is called ScopeGuard, called ScopeExit in Boost.
The idea is that you define some code you want to run at the end of the scope when you first make your changes, and the rest is handled. You can "dismiss" the code if desired.
I'd type an example but I'm on my phone.
RAII is for disposing resources, which isn't as constrained a concept as some might have you believe. "resource" can be substituted with "state" in many contexts.
If you equate a control's visibility with a stored state, and you need to safely reclaim that state (set it invisible), then resetting it in a destructor is the way to go.
You are using RAII correctly.
Be sure to name your class something that makes it plainly obvious that you are treating visibility as a disposable resource - maybe something as simple as VisibleState
or IsVisibleContext
.
I've done with C++ lambda and 2 macros:
#include <functional>
struct _Scope_Exit_ {
inline _Scope_Exit_(const std::function<void ()> f): _f(f) {}
inline ~_Scope_Exit_() { _f(); }
const std::function<void ()> _f;
};
#define SCOPE_EXIT_CAT2(x, y) x##y
#define SCOPE_EXIT_CAT1(x, y) SCOPE_EXIT_CAT2(x, y)
#define SCOPE_EXIT _Scope_Exit_ SCOPE_EXIT_CAT1(_scope_Exit_, __COUNTER__)([this](){
#define SCOPE_EXIT_END });
To use it, you must define the block that you want to execute at the end of the method between SCOPE_EXIT
and SCOPE_EXIT_END
In your sample would be:
widget1->show();
...
widgetN->show();
SCOPE_EXIT
widget1->hide();
...
widgetN->hide();
SCOPE_EXIT_END
... (code inside your try)
精彩评论