The vast majority of Event Callback functions will be executed quickly and will not lead to the death of the interface. The event model of the nana library is the sequential processing of the event queue, which means that the next event will be called only after the current event processing function is complete.
Consider the following example:
#include <nana/gui/wvl.hpp>#include <nana/gui/widgets/button.hpp>#include <nana/gui/widgets/progress.hpp>class example : public nana::gui::form{public: example() { btn_start_.create(*this, nana::rectangle(10, 10, 100, 20)); btn_start_.caption(STR("Start")); btn_start_.make_event<nana::gui::events::click>(*this, &example::_m_start); btn_cancel_.create(*this, nana::rectangle(120, 10, 100, 20)); btn_cancel_.caption(STR("Cancel")); btn_cancel_.make_event<nana::gui::events::click>(*this, &example::_m_cancel); prog_.create(*this, nana::rectangle(10, 40, 280, 20)); }private: void _m_start() { working_ = true; btn_start_.enabled(false); prog_.amount(100); for(int i = 0; i < 100 && working_; ++i) { nana::system::sleep(1000); //a long-running simulation prog_.value(i + 1); } btn_start_.enabled(true); } void _m_cancel() { working_ = false; }private: bool working_; nana::gui::button btn_start_; nana::gui::button btn_cancel_; nana::gui::progress prog_;};int main(){ example ex; ex.show(); nana::gui::exec(); return 0;}
This simple program simulates a time-consuming operation. A start button and a Cancel button indicate the start and stop tasks respectively. It is hard to imagine that _ m_start () will execute a time-consuming operation. When you press the "Start" button, the interface will be suspended. In this case, clicking "cancel" is useless, because the event processing for the start button is not over yet, and all you can do is wait. You can see that even if you release the mouse, the button is still pressed because the click event is still being processed.
Generally, to solve such time-consuming problems, place the time-consuming processing process in a separate thread, so that the UI thread has idle time to respond to user operations. When time-consuming operations are completed, it returns the result to the UI thread.
Consider the following solution:
#include <nana/gui/wvl.hpp>#include <nana/gui/widgets/button.hpp>#include <nana/gui/widgets/progress.hpp>#include <nana/threads/pool.hpp>class example : public nana::gui::form{public: example() { btn_start_.create(*this, nana::rectangle(10, 10, 100, 20)); btn_start_.caption(STR("Start")); btn_start_.make_event<nana::gui::events::click>(nana::threads::pool_push(pool_, *this, &example::_m_start)); btn_cancel_.create(*this, nana::rectangle(120, 10, 100, 20)); btn_cancel_.caption(STR("Cancel")); btn_cancel_.make_event<nana::gui::events::click>(*this, &example::_m_cancel); prog_.create(*this, nana::rectnagle(10, 40, 280, 20)); this->make_event<nana::gui::events::unload>(*this, &example::_m_cancel); }private: void _m_start() { working_ = true; btn_start_.enabled(false); prog_.amount(100); for(int i = 0; i < 100 && working_; ++i) { nana::system::sleep(1000); //a long-running simulation prog_.value(i + 1); } btn_start_.enabled(true); } void _m_cancel() { working_ = false; }private: volatile bool working_; nana::gui::button btn_start_; nana::gui::button btn_cancel_; nana::gui::progress prog_; nana::threads::pool pool_;};int main(){ example ex; ex.show(); nana::gui::exec(); return 0;}
The Nana Library provides a thread pool class. To solve such problems, you can use the thread pool to get rid of thread management, such as creation, waiting, and destruction. The above two sections of code are very similar, but the main difference is that _ m_start () is assigned to the thread pool and has a thread pool, and there are threads in the pool for processing, therefore, the UI thread is not blocked and has free time to respond to user operations.
Here is a function called pool_push (), which creates a pool_pusher function object to push the _ m_start () function into the thread pool. In other words, the pool_pusher function object is treated as an event, when the start button is clicked, pool_pusher is called and _ m_start () is pushed to the thread pool for execution.
In this version, the form object registers an unload event and calls _ m_cancel (). When the window is closed, the program abandons the remaining time-consuming operations. However, there is a question to be answered here. When time-consuming operations are still working, closing the window will cause the buttons and progress bars to be destroyed, but the time-consuming operation ends, if time-consuming operations access buttons and progress bar objects at this time, will the program crash? The answer is yes, but the above Code will avoid destroying the button and progress bar before the time-consuming operation is completed. In the class, the object Declaration of the thread pool is after the button and progress bar, this means that the thread pool will be destructed before the button and progress bar. When the thread pool is destructed, it will wait until all the worker threads have ended.
Handle blocking operations in background threads
In some cases, time-consuming work cannot be canceled or the current progress is unknown. Programs usually use a rolling progress bar to indicate that they are being processed.
#include <nana/gui/wvl.hpp>#include <nana/gui/widgets/button.hpp>#include <nana/gui/widgets/progress.hpp>#include <nana/threads/pool.hpp>class example : public nana::gui::form{public: example() { using namespace nana::gui; btn_start_.create(*this, nana::rectnagle(10, 10, 100, 20)); btn_start_.caption(STR("Start")); btn_start_.make_event<events::click>(nana::threads::pool_push(pool_, *this, &example::_m_start)); btn_start_.make_event<events::click>(nana::threads::pool_push(pool_, *this, &example::_m_ui_update)); prog_.create(*this, nana::rectangle(10, 40, 280, 20)); prog_.style(false); this->make_event<events::unload>(*this, &example::_m_cancel); }private: void _m_start() { btn_start_.enabled(false); nana::system::sleep(10000); //a blocking simulation btn_start_.enabled(true); } void _m_ui_update() { while(btn_start_.enabled() == false) { prog_.inc(); nana::system::sleep(100); } } void _m_cancel(const nana::gui::eventinfo& ei) { if(false == btn_start_.enabled()) ei.unload.cancel = true; }private: nana::gui::button btn_start_; nana::gui::progress prog_; nana::threads::pool pool_;};int main(){ example ex; ex.show(); nana::gui::exec(); return 0;}
Click the start button, and the program will push _ m_start () and _ m_ui_update () to the thread pool. Is it easy?
You are welcome to give your comments and suggestions for further discussion.