Event System: Difference between revisions
(Created page with "== neoGFX Event System == The neoGFX event system is both modern and simple and is an improvement over traditional signals and slots. To create an event handler simply use a lambda expression thus: <code> button1.clicked([](){ →... code ...: }); </code> If automatic event handler de-registration (traditional role of a "slot") is wanted: <code> neoGFX::sink s; s += button1.clicked([](){ →... code ...: }); </code> When 's' is destroyed any associated event re...") |
No edit summary |
||
(15 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
The ''neoGFX'' event system is a modern, simple improvement over traditional signals and slots. | |||
The neoGFX event system is | |||
To create an event handler simply use a lambda expression thus: | To create an event handler simply use a lambda expression thus: | ||
< | <pre> | ||
button1.clicked([](){ /* ... code ... */ }); | button1.clicked([](){ /* ... code ... */ }); | ||
</ | </pre> | ||
If automatic event handler de-registration (traditional role of a "slot") is wanted: | If automatic event handler de-registration (traditional role of a "slot") is wanted: | ||
< | <pre> | ||
neogfx::sink s; | |||
s += button1.clicked([](){ /* ... code ... */ }); | s += button1.clicked([](){ /* ... code ... */ }); | ||
</ | </pre> | ||
When | When <code>s</code> is destroyed any associated event registrations are de-registered automatically. Sink objects can be on the stack, member variables or the more traditional slot-like base class sub-object. | ||
The event system is fully multi-threaded. If you want to handle the event in the same thread that is emitting the event rather than the thread that created the event handler then one simply uses the ''thread snake'', <nowiki>~~~~</nowiki>, which has the nice side effect of making it obvious that the lambda is being executed in a thread that may be different to that which is running the surrounding code: | The event system is fully multi-threaded. If you want to handle the event in the same thread that is emitting the event rather than the thread that created the event handler then one simply uses the ''thread snake'', <code><nowiki>~~~~</nowiki></code>, which has the nice side effect of making it obvious that the lambda is being executed in a thread that may be different to that which is running the surrounding code: | ||
<pre> | <pre> | ||
Line 32: | Line 30: | ||
{ | { | ||
public: | public: | ||
define_event(OurEvent, our_event, int) | |||
public: | public: | ||
void something() | void something() | ||
{ | { | ||
// Using event object directly | |||
OurEvent.trigger(42); // by default a synchronous trigger | |||
OurEvent.sync_trigger(42); // synchronous trigger | |||
OurEvent.async_trigger(42); // asynchronous trigger | |||
// Using event (virtual) function | |||
our_event().trigger(42); // by default a synchronous trigger | |||
our_event().sync_trigger(42); // synchronous trigger | |||
our_event().async_trigger(42); // asynchronous trigger | |||
} | } | ||
}; | |||
class i_xyzzy // an interface (abstract base) class | |||
{ | |||
public: | |||
declare_event(our_event, int) | |||
public: | |||
virtual ~i_xyzzy() = default; | |||
public: | |||
virtual void qux() = 0; | |||
/* ... other interface methods or helper functions ... */ | |||
}; | |||
class xyzzy : public i_xyzzy // a concrete class implementing the above interface | |||
{ | |||
public: | |||
define_declared_event(OurEvent, our_event, int) | |||
public: | |||
void qux() final {} | |||
/* ... code ... */ | |||
}; | }; | ||
</pre> | </pre> |
Latest revision as of 12:03, 5 May 2024
The neoGFX event system is a modern, simple improvement over traditional signals and slots.
To create an event handler simply use a lambda expression thus:
button1.clicked([](){ /* ... code ... */ });
If automatic event handler de-registration (traditional role of a "slot") is wanted:
neogfx::sink s; s += button1.clicked([](){ /* ... code ... */ });
When s
is destroyed any associated event registrations are de-registered automatically. Sink objects can be on the stack, member variables or the more traditional slot-like base class sub-object.
The event system is fully multi-threaded. If you want to handle the event in the same thread that is emitting the event rather than the thread that created the event handler then one simply uses the thread snake, ~~~~
, which has the nice side effect of making it obvious that the lambda is being executed in a thread that may be different to that which is running the surrounding code:
/* ... code ... */ ~~~~machine.started([](){ /* ... code ... */ }); /* ... code ... */
For defining events and triggering them:
class foo { public: define_event(OurEvent, our_event, int) public: void something() { // Using event object directly OurEvent.trigger(42); // by default a synchronous trigger OurEvent.sync_trigger(42); // synchronous trigger OurEvent.async_trigger(42); // asynchronous trigger // Using event (virtual) function our_event().trigger(42); // by default a synchronous trigger our_event().sync_trigger(42); // synchronous trigger our_event().async_trigger(42); // asynchronous trigger } }; class i_xyzzy // an interface (abstract base) class { public: declare_event(our_event, int) public: virtual ~i_xyzzy() = default; public: virtual void qux() = 0; /* ... other interface methods or helper functions ... */ }; class xyzzy : public i_xyzzy // a concrete class implementing the above interface { public: define_declared_event(OurEvent, our_event, int) public: void qux() final {} /* ... code ... */ };