menubar — u_pbt_menubar #
← Component reference · Guide contents
Application menu bar: menus, submenus, checkable items, separators, icons and shortcuts — all drawn by the library, with no Windows menu involved.
▶ See it live — Demo application, Menu bar tile: the preview, the code behind it and this page, side by side.
At a glance #
| Userobject | u_pbt_menubar |
| Item class | n_pbt_menubar_item (one item) · n_pbt_menubar_menu (one menu of the bar) |
| Used for | Giving your window the application menu bar, themed like everything else |
| Principle | You declare the menus, then their items; every item is found again by its address menu/id |
Quick start #
// window open event
uo_menus.of_add_menu(/*key*/ "file", /*text*/ "File")
uo_menus.of_add_item(/*keys*/ "file/open", /*text*/ "Open")
uo_menus.of_add_item(/*keys*/ "file/save", /*text*/ "Save")
// event ue_item_selected : (string as_keys)
choose case as_keys
case "file/open"; of_open_document()
case "file/save"; of_save_document()
end choose
The model: three levels, one key per level #
A menu bar has three levels, and each is addressed by its key:
| Level | Added by | Key |
|---|---|---|
| The menu on the bar | of_add_menu | its key, file |
| The item of a menu | of_add_item | the address menu/item, file/open |
| The sub-item of an item | of_add_item | the address menu/item/sub-item, file/export/pdf — as deep as needed |
A key is unique under its parent only: that is why an item is always designated by its full address, the menu first — never by its key alone. Two menus can therefore each have their own open item, and two submenus their own pdf (file/export/pdf, file/print/pdf), without clashing. A key holds neither / nor |, is not empty and does not start with __: the adds refuse it (-5), as they refuse an address already taken or a parent never added.
A separator has no key:
of_add_separatordraws a line at the end of a menu (file) or of the cascade of an item (file/export), and there is nothing to read back afterwards.
Properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_theme_style | string | "" | Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change |
is_theme_mode | string | "" | Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change |
il_theme_accent | long | -1 | Accent colour of this component (-1 = the application accent, or the theme's) |
is_tooltip | string | "" | Plain tooltip shown when hovering the component |
is_super_tooltip_title | string | "" | Title of the rich tooltip (takes precedence over is_tooltip) |
is_super_tooltip_text | string | "" | Body of the rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the rich tooltip |
ib_wrap | boolean | false | false (default): the bar stays on one line; the titles that do not fit, from the end, go into the dropdown of a chevron at its end (their entries as cascades), and the height no longer changes. true: the bar wraps and announces its new height (ue_auto_height) — what it did before the 4.0 |
ib_track_hover | boolean | false | Subscription to ue_item_hover: without it the dropdowns do not even report the pointed entry — an event raised at every move of the pointer is only sent to an application that asked for it |
Item properties — n_pbt_menubar_item #
Obtained through of_item(address) — of_item("file/export/pdf"). An address of one level names a menu, not an item: its handle changes nothing, use of_menu.
| Property | Type | Default | Role |
|---|---|---|---|
is_text | string | — | Changes the item's label, live |
ib_enabled | boolean | true | Item is active; a greyed item no longer answers clicks |
ib_visible | boolean | true | Entry taken out of the list without being removed — submenu and shortcut asleep with it; it keeps its key and comes back as it was. An asleep shortcut keeps its chord: it does not reach your application either; is_shortcut = "" gives it back |
is_shortcut | string | "" | The accelerator displayed at the right of the item (Ctrl+S) — and armed: the chord raises ue_item_selected for that item wherever the focus is. A menu is where people learn the shortcuts of an application; a key shown that does nothing teaches the wrong thing. Keys: a letter, a digit, F1 to F24, Enter, Esc, Del, Insert, Home, End, PageUp, PageDown, and with Ctrl or Alt also +, -, ,, ., the arrows (Left…), Space, Tab, Backspace (Ctrl++ for zoom). A shortcut belongs on a leaf: on an item that opens a cascade it is neither shown nor fired. An empty string takes both away |
ib_checked | boolean | false | Check mark in front of the item — for an option that goes on and off |
is_image | string | "" | The item's icon, changed live: the item keeps its place in the list. Same paths as of_add_item (mono:, tint:, file.dll:NAME); an empty string takes it away |
is_group | string | "" | Makes the item a radio item: the items of one group under the same parent exclude each other — checking one (ib_checked = true, or the user's pick) unchecks the others, and a round bullet replaces the tick. ue_item_selected still tells you which one was picked. An empty string makes it an ordinary item again |
il_accent | long | -1 | Accent of this item: its tick, and its edge while pointed at (-1 = the theme's) |
il_back_color | long | -1 | Background of this item in the dropdown, at rest |
il_text_color | long | -1 | Text colour of this item |
il_back_color_hover | long | -1 | Background of this item while pointed at |
il_text_color_hover | long | -1 | Text colour of this item while pointed at |
is_tooltip | string | "" | Kept and read back, but an item of the dropdown shows no tooltip: the native dropdown has none. Only the menu titles show theirs (of_menu) |
is_super_tooltip_title | string | "" | Title of its rich tooltip — kept, not shown (see is_tooltip) |
is_super_tooltip_text | string | "" | Text of its rich tooltip — kept, not shown |
is_super_tooltip_image | string | "" | Image of its rich tooltip — kept, not shown |
Properties of a menu — n_pbt_menubar_menu #
Obtained through of_menu(key) — of_menu("file"). Colours and tooltip show on the menu title in the bar.
| Property | Type | Default | Role |
|---|---|---|---|
is_text | string | — | Caption of the menu, & included (mnemonic), changed without rebuilding the bar |
ib_enabled | boolean | true | Greyed menu: it no longer opens, its items and their shortcuts with it; the keyboard skips it |
ib_visible | boolean | true | The menu leaves the bar — items and shortcuts asleep with it — and comes back as it was. Asleep shortcuts keep their chord: it does not reach your application either |
is_align | string | "start" | u_pbt_menubar.ALIGN_END sets the menu at the end of the bar, like Help — with those that follow it in the same alignment, after it; ALIGN_START (default) puts it back among the others. Logical: the end is the left side in a right-to-left layout. With the chevron, the titles at the end fold first |
il_accent | long | -1 | Accent of this menu: a line under its title while its dropdown is open (-1 = none) |
il_back_color | long | -1 | Background of its title, at rest |
il_text_color | long | -1 | Text colour of its title, at rest |
il_back_color_hover | long | -1 | Background of its title when hovered or open |
il_text_color_hover | long | -1 | Text colour of its title when hovered or open |
is_tooltip | string | "" | Tooltip shown when the pointer rests on its title |
is_super_tooltip_title | string | "" | Title of the rich tooltip of its title |
is_super_tooltip_text | string | "" | Text of that rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of that rich tooltip |
Methods #
| Method | Role |
|---|---|
of_add_menu (string as_key, string as_text) | Adds a menu to the bar. Returns 0 once applied, -5 when the key is refused (empty, holding / or a vertical bar, starting with __, or already taken), -2 when the component is not created |
of_add_item (string as_keys, string as_text) | Adds an item at its address: file/open in the File menu, file/export/pdf under the Export item, as deep as needed. Returns 0 once applied, -5 when the address is refused: fewer than two levels, an empty level, a key holding / or a vertical bar or starting with __, a menu or a parent item never added, or an address already taken. -2 when the component is not created |
of_add_item (string as_keys, string as_text, string as_image, boolean ab_checked) | Same, with the icon and the tick. To grey the item, now or later, use its handle: of_item(address).ib_enabled = false. Returns 0 once applied, -5 when the address is refused: fewer than two levels, an empty level, a key holding / or a vertical bar or starting with __, a menu or a parent item never added, or an address already taken. -2 when the component is not created |
of_add_separator (string as_keys) | Draws a separator line at the end of a menu (file) or of the cascade of an item (file/export). Returns 0 once applied, -5 when nothing was added at that address, -2 when the component is not created |
of_add_header (string as_keys, string as_text) → long | Adds a section header at the end of a menu (view) or of the cascade of an entry (view/panels): a title line over the entries that follow it, until the next header or separator. It is not an entry — never chosen, never counted by of_count, nor in the demo cap — and it is not drawn when every entry it heads is hidden. Returns 0 once added, -5 when nothing was created at that address, -2 when the component is not created |
of_item (string as_keys) → n_pbt_menubar_item | Handle of an item, by its address — of_item("file/export/pdf") —, to read or set its properties. It is exactly what ue_item_selected hands you: the argument goes straight back in here. Never the key alone: two submenus may each hold a pdf, and only the address tells them apart. An address of one level names a menu: its handle changes nothing, use of_menu |
of_menu (string as_key) → n_pbt_menubar_menu | Handle of a top-level menu, to rename it or grey it out. of_add_menu could only do it at creation: greying Admin when the user logs out meant rebuilding the whole bar; ib_visible takes it out of the bar, entries and shortcuts asleep with it |
of_remove_item (string as_keys) → long | Removes one item, at its address (file/open, file/export/pdf) — its cascade with it; the others stay. Its handles are freed and its shortcut disarmed: the key goes back to your application. Without it there was only of_clear, which empties everything — the commonest dynamic menu, a recent files list, meant razing the whole bar on every document opened. Returns 0 once applied, -5 when no item lives at that address, -2 when the component is not created |
of_remove_menu (string as_key) → long | Removes a top-level menu, its items with it — handles freed, shortcuts disarmed. The bar is redrawn and its height announced again. Returns 0 once applied, -5 for a menu never added, -2 when the component is not created |
of_clear ( ) | Empties the bar — menus and items; their handles are freed and the shortcuts of the items disarmed. Returns 0 once applied, -2 when the component is not created |
of_reset ( ) | Empties the bar and puts every property back to its default. Returns 0 once applied, -2 when the component is not created |
of_set_redraw (boolean) | Groups a burst of changes into a single render. Returns 0 once applied, -2 when the component is not created |
of_save_as_png (string) · of_save_as_jpg (string) | Exports the rendering as an image. Returns 0 once the image is written, -4 when writing fails, -2 when the component is not created |
Events #
| Event | Raised when |
|---|---|
ue_menu_opening (string as_key) | Raised when a top-level menu is about to open — and the dropdown waits: it opens only once the event has returned. Enable, grey or fill its items here: the change shows in this opening, not the next one. Without it the whole bar had to be kept in step with the application state at all times, or show items that lie |
ue_menu_closed (string as_key) | The dropdown of a top-level menu closed without a choice: by the user (a click outside, Escape, or sliding to the next menu), or by your code removing, clearing, hiding or greying the open menu (of_remove_menu, of_clear, ib_visible, ib_enabled) — an order raises it too. Undo here what ue_menu_opening prepared (a preview, a selection). A pick raises ue_item_selected instead, and of_reset raises nothing |
ue_item_selected (string as_keys) | The user picked an item, or pressed its shortcut. as_keys is its address, the menu first — file/open, file/export/pdf: the key alone does not say which submenu it came out of, and two submenus may each hold their own. That same string goes straight back to of_item. An item greyed, hidden or removed while its dropdown was open raises nothing |
ue_item_hover (string as_keys) | With ib_track_hover = true: the entry under the pointer or the keyboard in an open dropdown, by its address (file/export/pdf) — a greyed entry too, its help can say why. Raised once per entry, then with an empty address when the dropdown closes (before ue_item_selected on a choice): write the help text of a status bar, then empty it |
ue_auto_height (long al_height) | The bar announces the height it needs — move whatever sits below it |
ue_ready ( ) | The component has finished loading; everything sent before was replayed |
ue_runtime_missing ( ) | The WebView2 runtime is missing: the component stays empty |
ue_bg_color (long al_color) | The component computed its theme background; the userobject already adopted it (backcolor) |
One line, by default. The titles that do not fit go into the chevron at the end of the bar (
ib_wrap = false, the default): the height stays that of one line andue_auto_heightis raised once. Withib_wrap = truethe bar wraps: it never scrolls, its height follows the rows andue_auto_heighttells you by how much at every change of width.
From the keyboard #
| Key | Effect |
|---|---|
| Alt · F10 | Hands the keyboard to the bar and underlines the letters of the menus, as in any Windows application; a second press gives it back |
| » | The chevron of the titles that do not fit: the arrows stop on it like on a title, Enter or Down opens the list of the hidden menus, and Alt + the letter of a hidden menu opens that menu from the chevron |
| Alt + letter | Opens the menu of that letter (&File) from any control of the window — a field, a DataWindow. An Alt+letter shortcut your application registered comes first. Two menus on the same letter: the band walks from one to the other, Enter opens. An accented or non-Latin letter is typed as on the keyboard (&Édition: Alt + the key of É) |
| Arrows | Walk the menus and their items, skipping greyed menus; right opens a sub-item, left goes back up. In right-to-left writing (RTL), everything turns round: on the bar, in the dropdown (aligned on the right edge of its title) and in the cascades, which open to the left — left opens, right goes back up |
| Enter | In a dropdown: picks the highlighted item (ue_item_selected). On a title of the bar, Enter, Space or Down arrow opens the menu. Space does not pick an item — the Windows rule too |
| Escape | Closes the open menu, then hands the focus back to the control that had it |
A menu bar never keeps the focus. A click on a title, then a pick with the mouse: the keyboard goes back to the control the user was typing in before
ue_item_selectedis raised.Edit > Pastetherefore pastes into the field being edited, andGetFocus()names it in the event.
Examples #
A complete menu bar #
// Freeze the drawing while you build
uo_menus.of_set_redraw(/*on*/ false)
// The File menu, with an icon on Open and a line before Quit
uo_menus.of_add_menu(/*key*/ "file", /*text*/ "&File")
uo_menus.of_add_item(/*keys*/ "file/open", /*text*/ "&Open...", /*image*/ "mono:img\packimages.dll:svg/samples/folder-open", /*checked*/ false)
uo_menus.of_add_separator(/*keys*/ "file")
uo_menus.of_add_item(/*keys*/ "file/quit", /*text*/ "&Quit")
// A submenu: Export, then its two formats
uo_menus.of_add_item(/*keys*/ "file/export", /*text*/ "&Export")
uo_menus.of_add_item(/*keys*/ "file/export/csv", /*text*/ "CSV")
uo_menus.of_add_item(/*keys*/ "file/export/pdf", /*text*/ "PDF")
// The View menu: an option that checks
uo_menus.of_add_menu(/*key*/ "view", /*text*/ "&View")
uo_menus.of_add_item(/*keys*/ "view/grid", /*text*/ "&Grid", /*image*/ "", /*checked*/ true)
// One single redraw, with everything
uo_menus.of_set_redraw(/*on*/ true)
Check, uncheck, grey out #
// The user toggled the grid display
uo_menus.of_item(/*keys*/ "view/grid").ib_checked = not uo_menus.of_item(/*keys*/ "view/grid").ib_checked
// An item that no longer applies is greyed, not removed:
// the user has to be able to see that it exists
uo_menus.of_item(/*keys*/ "file/save").ib_enabled = false
Radio items and a zoom shortcut #
// Two RADIO items: checking one unchecks the other, a round bullet replaces the tick
uo_menus.of_add_item(/*keys*/ "view/small", /*text*/ "&Small icons")
uo_menus.of_add_item(/*keys*/ "view/large", /*text*/ "&Large icons")
uo_menus.of_item(/*keys*/ "view/small").is_group = "size"
uo_menus.of_item(/*keys*/ "view/large").is_group = "size"
uo_menus.of_item(/*keys*/ "view/large").ib_checked = true
// Zoom: Ctrl++ is shown AND armed, wherever the focus is
uo_menus.of_add_item(/*keys*/ "view/zoomin", /*text*/ "Zoom &in")
uo_menus.of_item(/*keys*/ "view/zoomin").is_shortcut = "Ctrl++"
Rebuilding the bar #
// Switching workspace: empty, then fill again
// of_set_redraw avoids repainting on every line
uo_menus.of_set_redraw(/*on*/ false)
uo_menus.of_clear()
uo_menus.of_add_menu(/*key*/ "tools", /*text*/ "&Tools")
uo_menus.of_set_redraw(/*on*/ true)
A narrow bar, Help at the end, a help text in the status bar #
// Help at the end of the bar ; what does not fit goes into the chevron
uo_menubar.of_menu(/*key*/ "help").is_align = u_pbt_menubar.ALIGN_END
// Section headers in View
uo_menubar.of_add_header(/*keys*/ "view", /*text*/ "Panels")
uo_menubar.of_add_item(/*keys*/ "view/tree", /*text*/ "Tree")
uo_menubar.of_add_item(/*keys*/ "view/output", /*text*/ "Output")
// A help text in the status bar for the pointed entry
uo_menubar.ib_track_hover = true
// ue_item_hover (string as_keys) of uo_menubar
choose case as_keys
case "file/save"
st_status.Text = "Saves the document"
case ""
st_status.Text = ""
end choose
Best practices #
- Give a stable business key to every level (
file,save):ue_item_selectedreturns the addressfile/save, never the label — it does not change with the language. - Grey out rather than remove: a missing item leaves the user searching, a greyed one tells them it exists and that something is missing.
- Wrap the build in
of_set_redraw(false)/of_set_redraw(true): a complete bar is thirty calls in no time. - Move whatever sits under the bar in
ue_auto_height— the height depends on the theme and the font size, it is not the same everywhere. - The labels are yours: translate them before
of_add_item, or change them live throughof_item(...).is_text/of_menu(...).is_text.of_set_translationonly translates the texts a component has of its own, and the menu bar has none. - Put an
&in every title (&File): Alt + the letter opens the menu from anywhere, as in any Windows application.
Inherited from the common base #
These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.
| Members | Role | Detailed in |
|---|---|---|
of_count · of_keys_at · of_has | Walk what the component holds | 3.2 Items |
of_reset | Put the component back to zero | 3.6 Resetting a component: of_reset() |
of_register_shortcut · of_clear_shortcuts | The component's keyboard chords | 3.5 Keyboard shortcuts |
of_is_created · of_is_ready · of_get_last_error | Whether it was born, whether it is ready, what failed | 3.7 Diagnostics |
of_save_as_png · of_save_as_jpg | Export the rendering as an image | 3.8 Exporting the rendering as an image |
of_set_redraw | Group changes into a single repaint | 3.10 Best practices |
of_preload_icons | Icons shown with no delay | Instant display: of_icon |
of_set_translation | Translate one of the component's labels | 5.2 Adapting a label: of_set_translation |
of_focus_webview | Give the component the focus | 6.4 Keyboard and focus |
of_print · of_print_to_pdf | Print, or write a PDF | 6.9 Printing |
of_set_property · of_get_property · of_component_name | Driving a property by its name | 3.1 The property engine |
Two helpers are not inherited: of_icon and of_escape_markup live on n_pbt_utils. Declare one — n_pbt_utils lnv_utils, nothing to create — and call them on it.