Fork me on GitHub
Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
libui-python
Logo
libui-python

Getting Started

  • Installation
  • Quick Start
  • Concepts

Tutorial

  • Tutorial
    • Hello World
    • State and Binding
    • Layouts
    • Controls
    • Tables
    • Menus and Dialogs
    • Drawing
    • Async
    • Building an App

Reference

  • Widget Reference
  • API Reference
    • libui.core — C Extension
    • libui.state — Reactive State
    • libui.loop — Threading & Event Loop
    • libui.node — Node Base & Build Infrastructure
    • libui.declarative — Declarative API
    • libui.widgets — Widget Nodes
  • Changelog
Back to top
View this page
Edit this page

Menus and Dialogs¶

Menus¶

Menus are defined with MenuDef and passed to app.build(). They must be created before the window (a libui-ng requirement):

"""Menus — file, edit, and help menus with various item types."""

import libui
from libui.declarative import (
    App,
    Window,
    VBox,
    Label,
    State,
    MenuDef,
    MenuItem,
    CheckMenuItem,
    MenuSeparator,
    QuitItem,
    PreferencesItem,
    AboutItem,
)


async def main():
    app = App()
    dark_mode = State(False)
    status = State("Use the menus above.")

    menus = [
        MenuDef(
            "File",
            MenuItem(
                "Open...",
                on_click=lambda: status.set(
                    f"Open: {app.open_file() or '(cancelled)'}"
                ),
            ),
            MenuItem(
                "Save As...",
                on_click=lambda: status.set(
                    f"Save: {app.save_file() or '(cancelled)'}"
                ),
            ),
            MenuSeparator(),
            QuitItem(),
        ),
        MenuDef(
            "Edit",
            CheckMenuItem(
                "Dark Mode",
                checked=dark_mode,
                on_click=lambda: status.set(f"Dark mode: {dark_mode.value}"),
            ),
            MenuSeparator(),
            PreferencesItem(),
        ),
        MenuDef(
            "Help",
            AboutItem(),
            MenuItem(
                "Documentation",
                on_click=lambda: app.msg_box(
                    "Help", "Visit the project repository for documentation."
                ),
            ),
        ),
    ]

    app.build(
        menus=menus,
        window=Window(
            "Menus",
            500,
            250,
            has_menubar=True,
            child=VBox(
                Label(text=status),
            ),
        ),
    )

    app.show()
    await app.wait()


libui.run(main())
Menus

Menu item types¶

Type

Description

MenuItem(name, on_click=...)

Regular clickable item

CheckMenuItem(name, checked=..., on_click=...)

Checkable item, optionally bound to State[bool]

MenuSeparator()

Visual separator line

QuitItem()

Platform quit item (Cmd+Q / Alt+F4)

PreferencesItem()

Platform preferences item

AboutItem()

Platform about item

Set has_menubar=True on the Window to display the menu bar.

Dialogs¶

App provides dialog methods for file selection and message boxes:

"""Dialogs — file dialogs and message boxes (sync and async)."""

import libui
from libui.declarative import App, Window, VBox, Label, Button, State


async def main():
    app = App()
    status = State("")

    def do_open():
        path = app.open_file()
        status.set(f"Opened: {path}" if path else "Open cancelled.")

    def do_folder():
        path = app.open_folder()
        status.set(f"Folder: {path}" if path else "Folder cancelled.")

    async def do_save_async():
        path = await app.save_file_async()
        status.set(f"Save to: {path}" if path else "Save cancelled.")

    app.build(
        window=Window(
            "Dialogs",
            400,
            300,
            child=VBox(
                Label(text=status),
                Button("Open File", on_clicked=do_open),
                Button("Open Folder", on_clicked=do_folder),
                Button("Save File (async)", on_clicked=do_save_async),
                Button(
                    "Message Box",
                    on_clicked=lambda: app.msg_box("Info", "This is a message box."),
                ),
                Button(
                    "Error Box",
                    on_clicked=lambda: app.msg_box_error(
                        "Error", "Something went wrong!"
                    ),
                ),
            ),
        )
    )

    app.show()
    await app.wait()


libui.run(main())

Sync vs async dialogs¶

Dialog methods come in two flavors:

Sync (from main thread callbacks)

Async (from coroutines)

app.open_file()

await app.open_file_async()

app.open_folder()

await app.open_folder_async()

app.save_file()

await app.save_file_async()

app.msg_box(title, text)

await app.msg_box_async(title, text)

app.msg_box_error(title, text)

await app.msg_box_error_async(title, text)

Use sync methods inside on_clicked lambdas (which run on the main thread). Use async methods inside async def callbacks.

File dialog methods return a path string, or None if the user cancelled.

Next
Drawing
Previous
Tables
Copyright © 2024, libui-python contributors
Made with Sphinx and @pradyunsg's Furo
On this page
  • Menus and Dialogs
    • Menus
      • Menu item types
    • Dialogs
      • Sync vs async dialogs