Struct winsafe::gui::WindowMain [−][src]
pub struct WindowMain { /* fields omitted */ }
Expand description
An user main window, which can handle events. Usually, this is the first
window of your application, launched directly from the main
function. Can
be programmatically created or load a dialog resource from a .res
file.
Implements Parent
trait.
Examples
The two examples below show how to create the main window: programmatically,
or by loading a dialog resource from a .res
file.
Programmaticaly creating a window
Below is a full application based on a non-dialog WindowMain
, whose
instance is kept within MyMain
struct. This is not necessary, but is
highly recommended, because it makes it easier to manage the window
contents.
The main
function instantiates MyMain
by calling MyMain::new
, which
then calls WindowMain::new
. Note how it receives a WindowMainOpts
argument, who defines all the options.
The window is handling the mouse click event with a closure, and it displays the clicked coordinates in the title bar.
#![windows_subsystem = "windows"]
use winsafe::{gui, msg, BoxResult};
fn main() {
let my_main = MyMain::new();
if let Err(e) = my_main.wnd.run_main(None) {
eprintln!("{}", e);
}
}
pub struct MyMain {
wnd: gui::WindowMain,
}
impl MyMain {
pub fn new() -> MyMain {
let wnd = gui::WindowMain::new(
gui::WindowMainOpts {
title: "My window".to_owned(),
..Default::default()
},
);
let new_self = Self { wnd };
new_self.events();
new_self
}
fn events(&self) {
self.wnd.on().wm_l_button_down({
let wnd = self.wnd.clone(); // clone to pass it to the closure
move |p: msg::wm::LButtonDown| -> BoxResult<()> {
let txt = &format!("Coords {} x {}", p.coords.x, p.coords.y);
wnd.hwnd().SetWindowText(txt)?;
Ok(())
}
});
}
}
Loading a window resource from a .res
file
A window can also be loaded from a Win32 resource file (usually a .res
file). Below, a full aplication where WindowMain
loads a window resource,
instead of creating the window programmatically. Note how
WindowMain::new_dlg
instead of WindowMain::new
.
#![windows_subsystem = "windows"]
use winsafe::gui;
const ID_DLG_MAIN: i32 = 101; // in our .res file, this is the dialog ID
fn main() {
let my_main = MyDlg::new();
if let Err(e) = my_main.dlg.run_main(None) {
eprintln!("{}", e);
}
}
pub struct MyDlg {
dlg: gui::WindowMain,
}
impl MyDlg {
pub fn new() -> MyDlg {
let dlg = gui::WindowMain::new_dlg(ID_DLG_MAIN, None, None);
let new_self = Self { dlg };
new_self.events();
new_self
}
fn events(&self) {
}
}
Implementations
Instantiates a new WindowMain
object, to be created with
HWND::CreateWindowEx
.
Instantiates a new WindowMain
object, to be loaded from a dialog
resource with HWND::GetDlgItem
.
Returns the underlying handle for this control.
Note that the handle is initially null, receiving an actual value only after the control is created.
Exposes the window events.
Panics
Panics if the window is already created. Events must be set before window creation.
If you perform a very long task in the UI thread, the UI freezes until the task is complete – this may cause the impression that your application crashed. That’s why long tasks are performed in parallel threads. However, at some point you’ll want to update the UI to reflect the task progress, but if you update the UI from another thread (different from the original UI thread), the UI may deadlock, and you application crashes.
The run_ui_thread
method allows UI updates by running a closure
synchronously in the window’s original UI thread.
This is what this run_ui_thread
does, step-by-step:
- blocks current thread;
- switches to the window’s original UI thread;
- runs the given
FnOnce
; - switches back to the first thread, which is then unblocked.
When working in a parallel thread, you must call run_ui_thread
to
update the UI.
Examples
The example below shows the event of a button click which starts a long task in a parallel thread. As it progresses, the status is printed at the windows’s titlebar.
use winsafe::{gui, BoxResult, GetCurrentThreadId, Sleep};
let wnd: gui::WindowMain; // initialized somewhere
let btn: gui::Button;
btn.on().bn_clicked({
let wnd = wnd.clone();
move || -> BoxResult<()> {
println!("Click event at {:#x}", GetCurrentThreadId());
std::thread::spawn({
let wnd = wnd.clone();
move || {
println!("Parallel task starts at {:#x}", GetCurrentThreadId());
Sleep(2000);
wnd.run_ui_thread({
let wnd = wnd.clone();
move || -> BoxResult<()> {
println!("Updating UI at {:#x}", GetCurrentThreadId());
wnd.hwnd().SetWindowText("Status... 50%")?;
Ok(())
}
});
println!("Parallel task keeps going at {:#x}", GetCurrentThreadId());
Sleep(2000);
wnd.run_ui_thread({
let wnd = wnd.clone();
move || -> BoxResult<()> {
println!("Updating UI at {:#x}", GetCurrentThreadId());
wnd.hwnd().SetWindowText("Status... 100%")?;
Ok(())
}
});
}
});
Ok(())
}
});
Trait Implementations
Auto Trait Implementations
Blanket Implementations
Mutably borrows from an owned value. Read more