Sample 1: Simple GUI Events Handling

This sample introduces Channel by showing how to implement event handling thru Channel.

We first include the channel header file

#include <boost/channel/channel.hpp>

As a first step, instantiate a concrete channel type according to application's requirement. We could consider what data type to use as ids, and what kind of namespace and dispatcher will be best fit the application. Here we use strings as ids and use default linear_namespace and broadcast dispatcher:

typedef channel<string> evt_chan;
Next we define a few event ids to simulate some possible events inside a GUI window:
string down_id = "_window_button_down_";
string up_id = "_window_button_up_";
string close_id = "_window_close_";

In this sample, we use the following message/event data structure to pass some data:
struct evt_data {
string data_; 
evt_data(const char *d) : data_(d) {}
};

Then we define  the event source of this sample: a simplest GUI window without any features except those for sending events: bound channel and named_outs (also typedefed inside channel: evt_chan::out). Inside gui_window constructor, we bind named_outs to the above mentioned event ids in channel to send events:

class gui_window {
evt_chan & chan_;
 //a few event src
  evt_chan::out down_out_;
  evt_chan::out close_out_;
public:
gui_window(evt_chan & c): chan_(c),
down_out_(chan_, down_id),
up_out_(chan_, up_id),
close_out_(chan_, close_id) {}
...and define some utility methods to send out events thru named_outs ...
};

After defining event source, we define a handler class to demo using object methods as event callbacks. In constructor, we create named_in (also nested typedefed inside channel: evt_chan::in) objects to bind callbacks to event ids in channel namespace. Named_out and named_in objects can be created in stack as we have done in class gui_window. Here we create them by invoking channel's factory method to create them from heap.
class window_handler {
  evt_chan & ch_;
  //a few event sinks
  evt_chan::in *down_in_;
  evt_chan::in *up_in_;
  evt_chan::in *close_in_; 
public:
  window_handler(evt_chan & c): ch_(c) {
    down_in_ = ch_.bind_name_in(down_id, boost::bind(&window_handler::down, this, _1, _2));
    up_in_ = ch_.bind_name_in(up_id, boost::bind(&window_handler::up, this, _1, _2));
    close_in_ = ch_.bind_name_in(close_id, boost::bind(&window_handler::close, this, _1, _2));
  }
.... here define methods as event callbacks ...
};

We define another global function to be used  as event handler.
void evt_handler(string id, boost::shared_ptr<void> p)
{
  cout << "free handler ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
}

Now here is a simple main function:
int main(int, char **) {
The first thing is to create the event channel
evt_chan chan;
create the event source (gui_window) and bind it to channel
gui_window window(chan);
create a handler object and bind it to channel
 window_handler hdlr(chan);
Next we create more event sinks to bind the global function to event ids.
evt_chan::in window_down_in(chan, down_id, evt_handler)
evt_chan::in window_up_in(chan, up_id, evt_handler); 
evt_chan::in shut_down_in(chan, close_id, evt_handler);
Last, we fire some events
window.up("..Hi there [mouse-left-up] ..");
window.down(".. a simple window test [mouse-right-down] ..");
window.close(".. simple window wiered [window-closed] ..");
Then exit
cout << "... exit ...\n"; 
return 0;


In this simple sample, we bind event handlers/callbacks to event sources indirectly by binding to names in channel namespace. After namespace binding, event dispatching happens directly between named_out (senders) and named_in (receivers).


Finally, here is the complete source code.