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:

  1. blocks current thread;
  2. switches to the window’s original UI thread;
  3. runs the given FnOnce;
  4. 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(())
    }
});

Physically creates the window, then runs the main application loop. This method will block until the window is closed.

The cmd_show parameter defaults to co::SW::SHOW.

Panics

Panics if the window is already created.

Trait Implementations

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

Returns a reference to the Any trait, allowing downcasting.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Performs the conversion.

Performs the conversion.

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

Uses borrowed data to replace owned data, usually by cloning. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.