Trait winsafe::prelude::GuiParent

source ·
pub trait GuiParent: GuiWindow + AsRef<Base> {
    // Provided methods
    fn on(&self) -> &WindowEvents { ... }
    fn spawn_new_thread<F>(&self, func: F)
       where F: FnOnce() -> AnyResult<()> + Send + 'static { ... }
    fn run_ui_thread<F>(&self, func: F)
       where F: FnOnce() -> AnyResult<()> + Send + 'static { ... }
}
Available on crate features kernel and gui only.
Expand description

Any window which can host child controls.

Prefer importing this trait through the prelude:

use winsafe::prelude::*;

Provided Methods§

source

fn on(&self) -> &WindowEvents

Exposes methods to handle the basic window messages, plus timer and native control notifications.

§Panics

Panics if the window is already created. Events must be set before window creation.

source

fn spawn_new_thread<F>(&self, func: F)
where F: FnOnce() -> AnyResult<()> + Send + 'static,

This method calls std::thread::spawn, but it allows the returning of an error value. This error value will be forwarded to the original UI thread, allowing it to be caught at WindowMain::run_main.

It’s a way to ensure that, upon an unexpected error, you application will be terminated gracefully.

§Examples

The example below shows the event of a button click which spawns a new thread.

use winsafe::{self as w, prelude::*, gui};

let wnd: gui::WindowMain; // initialized somewhere
let btn: gui::Button;

btn.on().bn_clicked({
    let wnd = wnd.clone();
    move || -> w::AnyResult<()> {
        println!("Click event at {:#x}", w::GetCurrentThreadId());

        wnd.spawn_new_thread({
            let wnd = wnd.clone();
            move || {
                println!("This is another thread: {:#x}", w::GetCurrentThreadId());
                if 1 != 2 {
                    Err("Unexpected condition, goodbye.".into())
                } else {
                    Ok(())
                }
            }
        });

        Ok(())
    }
});
source

fn run_ui_thread<F>(&self, func: F)
where F: FnOnce() -> AnyResult<()> + Send + 'static,

Runs a closure synchronously in the window’s original UI thread, allowing UI updates without the risk of a deadlock.

§Rationale

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 should be 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.

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::{self as w, prelude::*, gui};

let wnd: gui::WindowMain; // initialized somewhere
let btn: gui::Button;

btn.on().bn_clicked({
    let wnd = wnd.clone();
    move || -> w::AnyResult<()> {
        println!("Click event at {:#x}", w::GetCurrentThreadId());

        std::thread::spawn({
            let wnd = wnd.clone();
            move || {
                println!("Parallel task starts at {:#x}", w::GetCurrentThreadId());
                w::Sleep(2000);

                wnd.run_ui_thread({
                    let wnd = wnd.clone();
                    move || -> w::AnyResult<()> {
                        println!("Updating UI at {:#x}", w::GetCurrentThreadId());
                        wnd.hwnd().SetWindowText("Status... 50%")?;
                        Ok(())
                    }
                });

                println!("Parallel task keeps going at {:#x}", w::GetCurrentThreadId());
                w::Sleep(2000);

                wnd.run_ui_thread({
                    let wnd = wnd.clone();
                    move || -> w::AnyResult<()> {
                        println!("Updating UI at {:#x}", w::GetCurrentThreadId());
                        wnd.hwnd().SetWindowText("Status... 100%")?;
                        Ok(())
                    }
                });
            }
        });

        Ok(())
    }
});

Object Safety§

This trait is not object safe.

Implementors§