PBToolboxAI v5 ← Site

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 #

Userobjectu_pbt_menubar
Item classn_pbt_menubar_item (one item) · n_pbt_menubar_menu (one menu of the bar)
Used forGiving your window the application menu bar, themed like everything else
PrincipleYou 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:

LevelAdded byKey
The menu on the barof_add_menuits key, file
The item of a menuof_add_itemthe address menu/item, file/open
The sub-item of an itemof_add_itemthe 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_separator draws 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 #

PropertyTypeDefaultRole
is_theme_stylestring""Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change
is_theme_modestring""Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change
il_theme_accentlong-1Accent colour of this component (-1 = the application accent, or the theme's)
is_tooltipstring""Plain tooltip shown when hovering the component
is_super_tooltip_titlestring""Title of the rich tooltip (takes precedence over is_tooltip)
is_super_tooltip_textstring""Body of the rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of the rich tooltip
ib_wrapbooleanfalsefalse (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_hoverbooleanfalseSubscription 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.

PropertyTypeDefaultRole
is_textstring—Changes the item's label, live
ib_enabledbooleantrueItem is active; a greyed item no longer answers clicks
ib_visiblebooleantrueEntry 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_shortcutstring""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. Armed once the item exists (of_add_item first): on an address that names no item, nothing is armed. Before acting, it raises ue_menu_opening of its menu
ib_checkedbooleanfalseCheck mark in front of the item — for an option that goes on and off
is_imagestring""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_groupstring""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
is_tonestring""The tone of the command: its text, at rest, in a colour of the light or dark theme — TONE_DANGER for the one that destroys, TONE_WARN, TONE_SUCCESS, TONE_INFO; empty or TONE_NEUTRAL = the text of the theme. Pointed at, the item takes the hover colours of the theme; an il_text_color of the item wins. The constants are on u_pbt_menubar
il_accentlong-1Accent of this item: its tick, and its edge while pointed at (-1 = the theme's)
il_back_colorlong-1Background of this item in the dropdown, at rest
il_text_colorlong-1Text colour of this item
il_back_color_hoverlong-1Background of this item while pointed at
il_text_color_hoverlong-1Text colour of this item while pointed at
is_tooltipstring""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_titlestring""Title of its rich tooltip — kept, not shown (see is_tooltip)
is_super_tooltip_textstring""Text of its rich tooltip — kept, not shown
is_super_tooltip_imagestring""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.

PropertyTypeDefaultRole
is_textstring—Caption of the menu, & included (mnemonic), changed without rebuilding the bar
ib_enabledbooleantrueGreyed menu: it no longer opens, its items and their shortcuts with it; the keyboard skips it
ib_visiblebooleantrueThe 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_alignstring"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_accentlong-1Accent of this menu: a line under its title while its dropdown is open (-1 = none)
il_back_colorlong-1Background of its title, at rest
il_text_colorlong-1Text colour of its title, at rest
il_back_color_hoverlong-1Background of its title when hovered or open
il_text_color_hoverlong-1Text colour of its title when hovered or open
is_tooltipstring""Tooltip shown when the pointer rests on its title
is_super_tooltip_titlestring""Title of the rich tooltip of its title
is_super_tooltip_textstring""Text of that rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of that rich tooltip

Methods #

MethodRole
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) → longAdds 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_itemHandle 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_menuHandle of a top-level menu, to read or change it live — grey, hide, rename, align or colour it — without rebuilding the bar; ib_visible takes it out of the bar, entries and shortcuts asleep with it
of_remove_item (string as_keys) → longRemoves 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. To empty a cascade and keep the item at its place: of_clear_items. 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) → longRemoves 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_insert_item (string as_keys, string as_text, integer ai_index) → longInserts an item at a rank of its list rather than at its end: as_keys is the address it will have (file/recent), ai_index its place among the items of that list, from 1 (0 or less = first; past the end = at the end). Separators and headers do not count: the item goes just before the one that held that rank. A recent files list thus stays at its place, above Exit. Returns 0 once applied, -5 when the address is refused (as of_add_item), -2 when the component is not created
of_insert_item (string as_keys, string as_text, string as_image, boolean ab_checked, integer ai_index) → longSame, with the icon and the tick, as of_add_item takes them. Returns 0 once applied, -5 when the address is refused, -2 when the component is not created
of_clear_items (string as_keys) → longEmpties a menu (file) or the cascade of an item (file/recent) and keeps the menu or the item at its place — what a recent files list rebuilt at each opening needs. The items that leave take their handles and their shortcuts with them. Returns 0 once applied, -5 when nothing was created at that address, -2 when the component is not created
of_open (string as_key) → longOpens the dropdown of a top-level menu from the code, as a click on its title would: ue_menu_opening is raised first, the dropdown shows at its answer, then ue_item_selected or ue_menu_closed. A menu folded into the chevron opens from the chevron. Returns 0 once asked, -5 for an unknown, hidden or greyed menu, -2 when the component is not created
of_close ( ) → longCloses the dropdown on screen — or a menu still opening — without a choice: ue_menu_closed follows, as for a click outside. Nothing open: nothing happens. Returns 0 once asked, -2 when the component is not created
of_is_open ( ) → booleanTRUE from the moment a menu opens — its ue_menu_opening went out — until it closes, by a choice or without one. Read from the component, never from a copy
of_load_menu (menu am_menu) → longBuilds the whole bar from a PowerBuilder menu — the menu of a window: each item of am_menu becomes a menu of the bar, its items the entries, cascades included, with their text (& marks kept), their state (Enabled, Checked, Visible), their toolbar picture when it is a file, and their Shortcut, shown and armed. Keys are the ClassNames of the items: m_file/m_export/m_pdf. The bar stays alive: before each opening (and before a shortcut acts) the Clicked of the title runs, as PowerBuilder runs it, then every item is read again: its text (the shortcut written after a tab included), Enabled, Checked and Visible. Choosing an entry runs the Clicked of its item first, then ue_item_selected; an item greyed meanwhile runs nothing (ue_menu_closed). A Clicked finds no ParentWindow: keep the window in an instance variable of the menu. The menu replaces what the bar held; keep the menu object alive. Returns 0 once loaded, -5 when am_menu is not valid, -2 when the component is not created
of_loaded_item (string as_keys) → menuThe PowerBuilder menu item a menu or an entry came from (of_load_menu), by its address — to read what the menu knows and the bar does not, its MicroHelp for a help line in ue_item_hover. An address that did not come from a menu gives an invalid reference: test it with IsValid
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 #

EventRaised when
ue_menu_opening (string as_key)Raised when a top-level menu is about to open — and the dropdown waits: it opens once the event has returned. Enable, grey or fill its items here: the change shows in this opening, not the next one. Raised too before a shortcut of one of its items acts, as Windows does: Paste greyed or enabled here answers Ctrl+V the same way. The chevron raises it once for each menu it shows. Every ue_menu_opening is followed by exactly one ue_item_selected or one ue_menu_closed — an opening given up before it showed included: what it prepared can always be undone
ue_menu_closed (string as_key)A menu closed without a choice: by the user (a click outside, Escape, or sliding to the next menu), by your code removing, clearing, hiding or greying the open menu or calling of_close, for an opening given up before its dropdown showed (sliding fast, Escape, the window losing the focus), and for a shortcut whose item ue_menu_opening greyed. 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. An entry of a PowerBuilder menu (of_load_menu) has already run the Clicked of its item
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. In the chevron's dropdown, a folded menu pointed at gives its key alone (tools): the help of that menu
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 and ue_auto_height is raised once. With ib_wrap = true the bar wraps: it never scrolls, its height follows the rows and ue_auto_height tells you by how much at every change of width. Opening the chevron raises ue_menu_opening for each menu it shows (and ue_menu_closed for each one at closing): an application that fills its lists at opening fills them all.


From the keyboard #

KeyEffect
Alt · F10Hands the keyboard to the bar and underlines the letters of the menus, as in any Windows application; a second press gives it back; Alt acts when it is released, alone: Alt+Shift (switching the keyboard layout) or Alt+Tab do not turn it on
»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 + letterOpens 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 É). Opened from the keyboard, the menu has its first item highlighted: Enter picks it
ArrowsWalk 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
EnterIn 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
EscapeCloses the open menu, or leaves the menu mode (after Alt or F10), then gives the focus back to the control that had it. Escape stays with the bar: it does not press the Cancel button of the window

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_selected is raised. Edit > Paste therefore pastes into the field being edited, and GetFocus() names it in the event. A click that opens nothing — on a greyed title, or on the empty part of the bar — also leaves the keyboard with the control the user was typing in.


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_menus.of_add_menu(/*key*/ "help", /*text*/ "&Help")
uo_menus.of_add_item(/*keys*/ "help/about", /*text*/ "About")
uo_menus.of_menu(/*key*/ "help").is_align = u_pbt_menubar.ALIGN_END

// Section headers in View
uo_menus.of_add_header(/*keys*/ "view", /*text*/ "Panels")
uo_menus.of_add_item(/*keys*/ "view/tree", /*text*/ "Tree")
uo_menus.of_add_item(/*keys*/ "view/output", /*text*/ "Output")

// A help text in the status bar for the pointed entry
uo_menus.ib_track_hover = true

// ue_item_hover (string as_keys) of uo_menus : empty when the dropdown closes
choose case as_keys
	case "file/save"
		st_status.Text = "Saves the document"
	case else
		st_status.Text = ""
end choose

A recent files list filled at opening #

// Local variables
long ll_i

// Recent at ITS place in File, declared once : its entries are written at each opening
uo_menus.of_insert_item(/*keys*/ "file/recent", /*text*/ "&Recent", /*index*/ 3)

// ue_menu_opening (string as_key) of uo_menus : the dropdown waits for it. File : the entries of
// Recent only, Recent keeps its place. Edit : Paste follows the clipboard of NOW - for a
// click as for Ctrl+V.
choose case as_key
	case "file"
		uo_menus.of_clear_items(/*keys*/ "file/recent")
		for ll_i = 1 to UpperBound(is_recent_files)
			uo_menus.of_add_item(/*keys*/ "file/recent/doc" + String(ll_i), /*text*/ is_recent_files[ll_i])
		next
	case "edit"
		uo_menus.of_item(/*keys*/ "edit/paste").ib_enabled = (Clipboard() <> "")
end choose

// ue_menu_closed (string as_key) of uo_menus : closed without a choice - undo what
// ue_menu_opening prepared
st_status.Text = ""

Taking over the PowerBuilder menu of a window #

// Local variables
menu lm_item

// The menu of the window becomes the bar : titles, entries, shortcuts, states.
// im_frame is an instance variable (m_frame), kept for as long as the bar uses it.
im_frame = create m_frame
uo_menus.of_load_menu(/*menu*/ im_frame)

// The menu stays the master : grey an item, the bar reads it at the next opening
im_frame.m_edit.m_paste.Enabled = false

// ue_item_hover (string as_keys) of uo_menus : the MicroHelp of the menu item
lm_item = uo_menus.of_loaded_item(/*keys*/ as_keys)
if IsValid(lm_item) then st_status.Text = lm_item.MicroHelp

Best practices #

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.

MembersRoleDetailed in
of_count · of_keys_at · of_hasWalk what the component holds3.2 Items
of_resetPut the component back to zero3.6 Resetting a component: of_reset()
of_register_shortcut · of_clear_shortcutsThe component's keyboard chords3.5 Keyboard shortcuts
of_is_created · of_is_ready · of_get_last_errorWhether it was born, whether it is ready, what failed3.7 Diagnostics
of_save_as_png · of_save_as_jpgExport the rendering as an image3.8 Exporting the rendering as an image
of_set_redrawGroup changes into a single repaint3.10 Best practices
of_preload_iconsIcons shown with no delayInstant display: of_icon
of_set_translationTranslate one of the component's labels5.2 Adapting a label: of_set_translation
of_focus_webviewGive the component the focus6.4 Keyboard and focus
of_print · of_print_to_pdfPrint, or write a PDF6.9 Printing
of_set_property · of_get_property · of_component_nameDriving a property by its name3.1 The property engine
is_accessible_name · is_accessible_descriptionThe name and description a screen reader says3.4 Optional properties and events

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.


← Component reference · Guide contents