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}; nwg_template!( head: setup_ui<&'static str>, controls: [ ("MainWindow", nwg_window!( title="Template Example"; size=(280, 105) )), ("Label1", nwg_label!( parent="MainWindow"; text="Your Name: "; position=(5,15); size=(80, 25); font=Some("TextFont") )), ("YourName", 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", "SaySomething", Event::Click, |ui,_,_,_| { let your_name = nwg_get!(ui; ("YourName", 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<&'static str>; 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.&'static str
if the ui is entirely static, or usize
if new controls will be created at runtime. 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}; pub fn setup_ui(ui: &Ui<&'static str>) -> 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(&"Label1", label); ui.pack_control(&"YourName", tedit); ui.pack_control(&"HelloButton", hellbtn); // events: ui.bind(&"HelloButton", &"SaySomething", Event::Click, |ui,_,_,_| { if let Ok(your_name) = ui.get::<nwg::TextInput>(&"YourName") { simple_message("Hello", &format!("Hello {}!", your_name.get_text()) ); } else { panic!() } }); ui.commit() } fn main() { let app: Ui<&'static str>; 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.