Skip to content

CheckBox

Header: winui/ui/input/CheckBox.hpp. Spec: winui/ui/input/CheckBox.hpp.

A box that is checked, unchecked or indeterminate, with an optional label to its right.

The value is a nullable bool: true, false, or std::nullopt for indeterminate. Compare it against a value instead of testing it for truth. if (box.checked()) asks whether the state is determinate and is true for an unchecked box, so write box.checked() == true. A click, Space (not Enter, which belongs to a dialog's default button) or UI Automation's Toggle advances the state; whether that can reach indeterminate is three_state().

Example:

auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
ui::CheckBoxControl* remember = stack->add(std::make_unique<ui::CheckBoxControl>("Remember me", /*checked=*/false));
ui::ButtonControl*   sign_in  = stack->add(std::make_unique<ui::ButtonControl>("Sign in"));
sign_in->set_enabled(false);
remember->on_checked_changed([sign_in](std::optional<bool> v) { sign_in->set_enabled(v == true); });
window.set_content(std::move(stack));

// Declaratively, bound both ways to a Property:
ui::Property<bool> remember_me{false};
window.set_content(ui::CheckBox{
    .text               = "Remember me",
    .checked            = remember_me,
    .on_checked_changed = [&](std::optional<bool> v) { remember_me = v.value_or(false); },
});

ui::CheckBox

A checkbox with a trailing label. Builds a ui::CheckBoxControl. checked is nullable: std::nullopt is indeterminate, and a plain true or false converts to it, so .checked = true works. three_state lets a click reach indeterminate.

ui::bind() of a Property<std::optional<bool>> is two-way: a click writes the new state back before .on_checked_changed runs.

Example:

ui::Property<std::optional<bool>> agreed{false};

window.set_content(ui::VerticalStack{
    .spacing  = 8,
    .content  = {
        ui::CheckBox{.text = "I agree", .checked = agreed},
        ui::Button{.text    = "Continue",
                   .enabled = ui::bind(agreed, [](std::optional<bool> on) { return on == true; })},
    },
});

Every field, in the order a designated initializer names them:

ui::CheckBox{
    .text, .checked, .three_state, .style, .margin, .width, .height, .min_width, .min_height,
    .max_width, .max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip,
    .enabled, .accessibility, .on_checked_changed, .on_pointer_entered, .on_pointer_exited,
    .on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control
}

Fields, in declaration order (designators must follow it):

Field Type Default
text ui::Binding<std::string> The label right of the box.
checked ui::CheckedField {false} True, false, or std::nullopt for indeterminate. Seeding it raises nothing. Two-way with a Property<bool> (a click writes true or false; an indeterminate state set on the control writes nothing) or a Property<std::optional<bool>> (every state). See ui::CheckedField.
three_state bool false A click also reaches indeterminate: unchecked, checked, indeterminate, unchecked. Without it, a click on an indeterminate box checks it. Needs checked bound to a Property<std::optional<bool>> (or one-way), since a Property<bool> cannot hold the third state; a debug build asserts on that. Read once, when the spec is built.
on_checked_changed ui::Callback<void(std::optional<bool>)> The new state, after a click, the keyboard or a bound value changed it.
on_pointer_entered ui::Action The pointer moved onto the control.
on_pointer_exited ui::Action The pointer left the control.
on_got_focus ui::Action Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this.
on_lost_focus ui::Action Keyboard focus left the control and everything inside it.
on_key_down ui::Callback<ui::Handling(const ui::KeyEvent&)> A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()).
on_wheel ui::Callback<ui::Handling(const ui::PointerEvent&)> A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()).
control ui::ControlOut<ui::CheckBox> Out: the handle that receives the built control.

Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, enabled, accessibility every spec carries (conventions).

build

std::unique_ptr<Element> build()&&

Consumes the spec and returns the built ui::CheckBoxControl; the caller owns it.

ui::CheckBoxControl

Derives from ui::Element, ui::ToggleProvider.

A box that is checked, unchecked or indeterminate, with an optional label to its right.

The value is a nullable bool: true, false, or std::nullopt for indeterminate. Compare it against a value instead of testing it for truth. if (box.checked()) asks whether the state is determinate and is true for an unchecked box, so write box.checked() == true. A click, Space (not Enter, which belongs to a dialog's default button) or UI Automation's Toggle advances the state; whether that can reach indeterminate is three_state().

Example:

auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
ui::CheckBoxControl* remember = stack->add(std::make_unique<ui::CheckBoxControl>("Remember me", /*checked=*/false));
ui::ButtonControl*   sign_in  = stack->add(std::make_unique<ui::ButtonControl>("Sign in"));
sign_in->set_enabled(false);
remember->on_checked_changed([sign_in](std::optional<bool> v) { sign_in->set_enabled(v == true); });
window.set_content(std::move(stack));

// Declaratively, bound both ways to a Property:
ui::Property<bool> remember_me{false};
window.set_content(ui::CheckBox{
    .text               = "Remember me",
    .checked            = remember_me,
    .on_checked_changed = [&](std::optional<bool> v) { remember_me = v.value_or(false); },
});

CheckBoxControl

CheckBoxControl() = default

An unlabeled, unchecked box.

CheckBoxControl

CheckBoxControl(std::string text, std::optional<bool> checked = false)

A box labeled text (UTF-8) in state checked (nullopt: indeterminate). Seeding the state raises nothing: no handler is attached yet.

text

const std::string& text() const

The label right of the box (UTF-8); empty draws the box alone. Also the automation name fallback.

set_text

void set_text(std::string text)

Sets the label (UTF-8). The box is measured again and redrawn.

checked

std::optional<bool> checked() const

True, false, or nullopt for indeterminate; false by default. Compare against a value (== true) instead of testing the optional for truth.

set_checked

void set_checked(std::optional<bool> checked)

Sets the state, allowed to be indeterminate even when not three_state(). Fires on_checked_changed() when the value changes, and redraws.

three_state

bool three_state() const

Whether clicking (or Space, or UI Automation's Toggle) cycles through indeterminate: unchecked -> checked -> indeterminate -> unchecked. Off, the cycle is unchecked <-> checked, and an indeterminate box set in code clicks to unchecked. Off by default.

set_three_state

void set_three_state(bool three_state)

Affects only the next click; the current state is left as it is.

on_checked_changed

void on_checked_changed(Callback<void(std::optional<bool>)> handler)

Invoked whenever checked changes (click, Space, or set_checked()), including into and out of indeterminate. Receives the new state. Replaces any previous handler.

parallel_measure_safe

bool parallel_measure_safe() const override

True: measuring reads only the box's own state, the measurer and the theme.

focused

bool focused() const

Whether the box holds keyboard focus.

focusable

bool focusable() const override

A disabled box is skipped in the tab order.

is_pressed

bool is_pressed() const

True while pressed by the pointer or a held Space.

automation_role

AutomationRole automation_role() const override

Always AutomationRole::CheckBox.

automation_name_fallback

std::string automation_name_fallback() const override

text(), used when Accessibility::name is not set.

visual_state

ButtonState visual_state() const

Disabled, Pressed, Hover or Normal, from the enabled flag and the pointer/key input.

measure_override

Size measure_override(Size available, const MeasureContext& context) const override

The box plus, when there is a label, the gap and the label's measured text.

pointer_override

bool pointer_override(const PointerEvent& e) override

A press and release inside the control (box or label) toggles it.

render_override

void render_override(Renderer& renderer, const RenderContext& context) const override

Draws the box (with its check or indeterminate dash), the label and the focus ring.

tick_override

void tick_override(Duration delta) override

In themes that animate the mark (the Fluent eras), draws the tick in (about 317 ms) when checked and erases it (67 ms) when cleared. The box's colors change at once and an indeterminate dash appears without animation. Until the box gets its first animation frame, and with animations off, the mark appears at once.

enabled_changed

void enabled_changed() override

is_enabled() flipped, through set_enabled() here or on an ancestor, or a move to another parent. Drop any press or hover state. The element is redrawn either way. No-op by default.

focus_changed

void focus_changed(bool focused) override

Called by Window. Losing focus cancels a Space press in progress. Redraws.

key_override

bool key_override(const KeyEvent& e) override

Space down presses, Space up toggles. Enter is not handled.

focus_ring_rect

Rect focus_ring_rect(const Theme& theme) const override

Around box and label in the Fluent eras, the label (or the box without one) in the classic ones, the box in Metro's.

focus_ring_corner_radius

float focus_ring_corner_radius(const Theme& theme) const override

The ring's corner radius: the theme's control radius by default.

Tests

  • tests/test_check_box.cpp