In this first chapter, you will install NWG and then look at a very simple application. This tutorial will intoduce the concepts of Control Templates, Events and the macro-based template system. These three compose the foundation of NWG. The next chapter "Basics" will go deeper into these.
cargo.toml:
[dependencies] native-windows-gui = "0.2.0"And then, in
main.rs or lib.rs :
extern crate native_windows_gui as nwg;
/** Simple example on how to use the nwg template system. */ #[macro_use] extern crate native_windows_gui as nwg; use nwg::{Event, Ui, simple_message, fatal_message, dispatch_events}; /// Custom enums are the preferred way to define ui ids. It's clearer and more extensible than any other types (such as &'str). #[derive(Debug, Clone, Hash)] pub enum AppId { // Controls MainWindow, NameInput, HelloButton, Label(u8), // Ids for static controls that won't be referenced in the Ui logic can be shortened this way. // Events SayHello, // Resources MainFont, TextFont } use AppId::*; // Shortcut nwg_template!( head: setup_ui<AppId>, controls: [ (MainWindow, nwg_window!( title="Template Example"; size=(280, 105) )), (Label(0), nwg_label!( parent=MainWindow; text="Your Name: "; position=(5,15); size=(80, 25); font=Some(TextFont) )), (NameInput, nwg_textinput!( parent=MainWindow; position=(85,13); size=(185,22); font=Some(TextFont) )), (HelloButton, nwg_button!( parent=MainWindow; text="Hello World!"; position=(5, 45); size=(270, 50); font=Some(MainFont) )) ]; events: [ (HelloButton, SayHello, Event::Click, |ui,_,_,_| { let your_name = nwg_get!(ui; (NameInput, nwg::TextInput)); simple_message("Hello", &format!("Hello {}!", your_name.get_text()) ); }) ]; resources: [ (MainFont, nwg_font!(family="Arial"; size=27)), (TextFont, nwg_font!(family="Arial"; size=17)) ]; values: [] ); fn main() { let app: Ui<AppId>; match Ui::new() { Ok(_app) => { app = _app; }, Err(e) => { fatal_message("Fatal Error", &format!("{:?}", e) ); } } if let Err(e) = setup_ui(&app) { fatal_message("Fatal Error", &format!("{:?}", e)); } dispatch_events(); }
Ui encapsulate the various components of NWG. Its role is to manage these components so that most of your energy is spent
developing the actual application instead of the UI. As of BETA 1, an application can instance as many Ui as it requires.
See the documentation for more information.usize can be used, but the result will not be as clear. The hash values are UI components (ex: the controls). Ui::new() method. The constructor execute some system initialization and therefore can fail.
Once the Ui is ready, it is now time to add stuff inside of it. The easiest way to do this is to use the built-in template system.
nwg_template! macro (documentation).
Its role is to define a function that initialize the Ui components.head defines the type of the Ui that will be accepted and the name of the function
The other parameters (controls, events, resources and values) are described in the following sections.Error is returned with some information about what went wrong.
The template content is ready to be used as soon as the function returns with success.
nwg_template! macro is controls. Controls accepts a list of (Control_ID, Control_Template).Control_ID is the unique ID that will identify the control in the Ui. Its type must match the type of the Ui. Control_Template is the template of the control. NWG control templates are structs that define controls. By default, the templates do not
have sane default. In order to ease the template definition, NWG has a macro named nwg_[control_name] (ex: button)
for each built-in control.nwg_template! macro is events. Events accepts a list of (Control_ID, Event_ID, Event_Type, Callback).Control_ID is the ID of the control that will trigger the event. Event_ID is a unique id that identify the event. Event_Type Is the event type. See a list of all events. Callback Is the function that will be called. The callback function signature is EventCallbacknwg_template! macro is resources.(Resource_ID, Resource_Template) that
will be created in the order they were added.nwg_template! macro is values. Values accepts a list of (Value_ID, ValueObject).
Resources creation works like controls and resources with the exception that ValueObject is the object itself and not some kind of template.
dispatch_events
function must be used. The method will dispatch the events to every instanced UI. As soon as a main window is closed (exit_on_close set to true) or if nwg::exit
is called, the function will return.
/** Simple example on how to use nwg without the template system. Unless your UI is built dynamically, the usage of the macro templates is highly recommended */ extern crate native_windows_gui as nwg; use nwg::{Ui, Error, Event, simple_message, fatal_message, dispatch_events}; #[derive(Debug, Clone, Hash)] pub enum AppId { // Controls MainWindow, NameInput, HelloButton, Label(u8), // Events SayHello, // Resources MainFont, TextFont } use AppId::*; // Shortcut pub fn setup_ui(ui: &Ui<AppId>) -> Result<(), Error> { // nwg_font!(family="Arial"; size=27) let f1 = nwg::FontT { family: "Arial", size: 27, weight: nwg::constants::FONT_WEIGHT_NORMAL, decoration: nwg::constants::FONT_DECO_NORMAL, }; // nwg_font!(family="Arial"; size=17) let f2 = nwg::FontT { family: "Arial", size: 17, weight: nwg::constants::FONT_WEIGHT_NORMAL, decoration: nwg::constants::FONT_DECO_NORMAL, }; // nwg_window!( title="Template Example"; size=(280, 105)) let window = nwg::WindowT { title: "No template", position: (100, 100), size: (280, 105), resizable: false, visible: true, disabled: false, exit_on_close: true }; // nwg_label!( parent="MainWindow"; [...] font=Some("TextFont") ) let label = nwg::LabelT { text: "Your Name: ", position: (5,15), size: (80, 25), visible: true, disabled: false, align: nwg::constants::HTextAlign::Left, parent: MainWindow, font: Some(TextFont) }; // nwg_textinput!( parent="MainWindow"; [..] font=Some("TextFont") ) let tedit = nwg::TextInputT::<_, &'static str, _> { text: "", position: (85,13), size: (185,22), visible: true, disabled: false, readonly: false, password: false, limit: 32_767, placeholder: None, parent: MainWindow, font: Some(TextFont) }; // nwg_button!( parent="MainWindow"; [..] font=Some("MainFont") ) let hellbtn = nwg::ButtonT { text: "Hello World!", position: (5, 45), size: (270, 50), visible: true, disabled: false, parent: MainWindow, font: Some(MainFont) }; // resources: ui.pack_resource(&MainFont, f1); ui.pack_resource(&TextFont, f2); // controls: ui.pack_control(&MainWindow, window); ui.pack_control(&Label(0), label); ui.pack_control(&NameInput, tedit); ui.pack_control(&HelloButton, hellbtn); // events: ui.bind(&HelloButton, &SayHello, Event::Click, |ui,_,_,_| { if let Ok(your_name) = ui.get::<nwg::TextInput>(&NameInput) { simple_message("Hello", &format!("Hello {}!", your_name.get_text()) ); } else { panic!() } }); ui.commit() } fn main() { let app: Ui<AppId>; match Ui::new() { Ok(_app) => { app = _app; }, Err(e) => { fatal_message("Fatal Error", &format!("{:?}", e) ); } } if let Err(e) = setup_ui(&app) { fatal_message("Fatal Error", &format!("{:?}", e)); } dispatch_events(); }
pack_control, pack_resource and pack_value add an element to the UI. The parameters works like in the nwg_template! macro.events fields of nwg_template!: bind a callback to a control.ui.get and ui.get_mut either borrows a control, a resource or a user value from the Ui. Obviously, any element can be borrowed immutably
as many time as required, but an element can only be borrowed mutably once. Error::ControlInUse will be raised.
pack_control and bind) wont be executed right away. Many of these commands are
used when creating a UI. With these conditions, they should never fail and validating each of them individually would be annoying.ui.commit() forces the execution of the waiting commands
and return an error if the initialization failed.