Event loop
AppCUI is an event-driven framework, meaning that each control can emit events to reflect various actions or changes that occur. For example, whenever you push a button, an event will be raised. All events are processed at window level by implementing various traits. To build a window that supports event handling, you must use a special procedural macro called Window, defined in the following way:
#[Window(events=..., )]
struct MyWindow {
// specific fields
}
where the attribute events has the following form:
events=EventTrait-1 + EventTrait-2 + EventTrait-3 + ... EventTrait-n
and an event trait can be one of the following:
- ButtonEvents
- CheckBoxEvents
- RadioBoxEvents
- WindowEvents
- MenuEvents
- CommandBarEvents
- ToolBarEvents
- ColorPickerEvents
- ThreeStateBoxEvents
- PasswordEvents
- KeySelectorEvents
- TextFieldEvents
These traits can be implemented to receive notifications about various actions that child controls are performing.
When creating a window that supports the event loop in this manner, you will need to instantiate it. A common approach is the following:
#[Window(events=..., )]
struct MyWindow {
// specific fields
}
impl MyWindow {
fn new(/* extra parameters */) -> Self {
let mut obj = MyWindow {
base: Window::new(title, layout, flags),
// initialize other fields from MyWindow here
};
// other initialization (such as creating children)
return obj;
}
}
The initialization base: Window::new(title, layout, flags), is mandatory. As for the title, layout, and flags, you can provide them as parameters in the new method, or you can infer or hardcode them in another way. Read more about how a window can be created on the Window page.
Once you create such a window, you can add it to your application using the add_window(...) method.
fn main() -> Result<(), appcui::system::Error> {
let mut app = App::new().build()?;
app.add_window(MyWindow::new(/* parameters */));
app.run();
Ok(())
}
A simple example
Let's start with a simple example that creates a window with a fixed size of 40x20 characters and two internal i32 values.
use appcui::prelude::*;
#[Window()]
struct MyWindow {
value1: i32,
value2: i32
}
impl MyWindow {
fn new(title: &str) -> Self {
MyWindow {
base: Window::new(title, layout!("a:c,w:40,h:20"), window::Flags::None),
value1: 0,
value2: 1,
}
}
}
fn main() -> Result<(), appcui::system::Error> {
let mut app = App::new().build()?;
app.add_window(MyWindow::new("Some title"));
app.run();
Ok(())
}
Intercepting events from a child control
Usually, a window that processes events maintains handles to various controls and enables event processing in the #[Window(...)] declaration.
use appcui::prelude::*;
#[Window(events = /*Events specific to a control */)]
struct MyWindow {
value1: i32,
control: Handle</*control type*/>
}
impl MyWindow {
fn new(/* parameters */) -> Self {
let mut mywin = MyWindow {
base: Window::new(/*...*/),
control: Handle::None,
};
// now we create the control
mywin.control = mywin.add(/* Code that creates a control */);
return mywin;
}
}
impl /*Control event*/ for MyWindow {
// add logic for event
}
fn main() -> Result<(), appcui::system::Error> {
let mut app = App::new().build()?;
app.add_window(MyWindow::new(/* parameters */));
app.run();
Ok(())
}
For every control described in Stock Controls, an example of how that control can be used with the event loop and the type of events it emits is presented.