angulargauge — u_pbt_angulargauge #
← Component reference · Guide contents
Dial: one value read on a circular scale — a needle, a filled arc or a marker on the rim, coloured ranges that say whether it is good, a target, a readout in the format of your choice.
▶ See it live — Demo application, Angular gauge tile: the preview, the code behind it and this page, side by side.
In brief #
| Userobject | u_pbt_angulargauge |
| Item class | n_pbt_angulargauge_range (of_range(key)) |
| Used for | Reading a quantity at a glance — a speed, a temperature, how far a goal is reached, a thermostat knob |
| Principle | You give a scale, a value and ranges; the graduations, the numbers, the colours and the animation are ours |
| Family | Twin of gauge: same methods, same events, and the same properties apart from the geometry — here the angles and the round ends, there the orientation and the placement of the ranges |
Quick start #
// A scale from 0 to 240, a number every 20
uo_dial.id_maximum = 240
uo_dial.id_tick_step = 20
// Three ranges of the scale, each with the tone of what it means
uo_dial.of_add_range(/*key*/ "city", /*from*/ 0, /*to*/ 130)
uo_dial.of_add_range(/*key*/ "fast", /*from*/ 130, /*to*/ 180)
uo_dial.of_add_range(/*key*/ "limit", /*from*/ 180, /*to*/ 240)
uo_dial.of_range(/*key*/ "city").is_tone = u_pbt_angulargauge.TONE_SUCCESS
uo_dial.of_range(/*key*/ "fast").is_tone = u_pbt_angulargauge.TONE_WARN
uo_dial.of_range(/*key*/ "limit").is_tone = u_pbt_angulargauge.TONE_DANGER
// The unit, and the value : the needle turns to it
uo_dial.is_unit = "km/h"
uo_dial.id_value = 96
The scale, the value and the ranges #
The scale runs from id_minimum to id_maximum (0 to 100 by default). The value id_value reads back as you gave it: outside the scale it is drawn pegged at the nearest end and the readout still writes it — a gauge that silently rewrote what the application measured would lie twice. Set by the code it raises no event, like SetItem: ue_value_changed says what the user did. NULL is ignored: the previous value stays — test a measure that may be missing (GetItemNumber returns NULL) before you set it.
The numbers follow is_format, the display format of a DataWindow (#,##0.0, $#,##0, 0% writes the PART of the scale — 50 on 0..200 reads 25%, as the progress bar does), with the separators of the display language. Without a format, the scale chooses the decimals of the readout — two for a scale of 0 to 1, none for 0 to 100 —, never the value, which would write 43 one second and 42.55 the next; the numbers of the scale take those of their step.
A range colours a portion of the scale: its colour is the one you give, otherwise that of its tone (TONE_SUCCESS, TONE_WARN, TONE_DANGER, TONE_INFO = the theme accent, TONE_NEUTRAL — one set of colours per light or dark mode), otherwise that of the palette. Ranges overlap in the order they were added; of_current_range() says which one the value is in. Under a needle they are the band; under a filled arc, a ring inside it. A range holds its start but not its end: on the end two ranges share (60 between 0–60 and 60–85), the value is in the one that starts there, whatever the order of the adds; the end of the scale belongs to the range that reaches it. The palette colour of a range is fixed when it is added: removing one recolours no other. A range entirely outside the scale is not drawn.
Angles are counted in degrees, 0 at the top, clockwise: by default the scale starts at -135 (bottom left) and covers 270 degrees — a speedometer. ii_start_angle = -90 and ii_sweep_angle = 180 give a half dial, drawn twice as large. A dial is a measuring instrument: it does not turn round in a right-to-left application.
Properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_title | string | "" | The title, above the dial. Markup accepted; it also names the component for a screen reader. Without a title, the plain text of the tooltip names it (is_super_tooltip_title, else is_tooltip), else the word “Gauge” in the display language |
id_value | double | 0 | The value. It slides to its place; outside the scale, drawn pegged and read back as given. Set by the code, silent; NULL is ignored, the previous value stays |
id_minimum | double | 0 | The start of the scale. A scale whose minimum is not below its maximum is empty: no graduation, no number, no range, no pointer and no target, and of_current_range() gives an empty string. To turn a scale round, ib_reversed |
id_maximum | double | 100 | The end of the scale |
is_format | string | "" | The display format of every number — readout, scale, ends of a range —, in the syntax of a DataWindow format (#,##0.00, $#,##0, 0%), separators of the display language. Empty = the readout takes the decimals of the scale (two for 0 to 1, none for 0 to 100), the numbers of the scale those of their step (0.0, 0.2… 1.0) |
is_unit | string | "" | Written after the value in the readout (%, km/h) |
ib_show_value | boolean | true | Shows the readout — the value and its unit — under the pivot of a needle (below the numbers of the two ends on a small dial), in the middle of a filled arc. Without it, a needle dial is drawn larger |
id_tick_step | double | 0 | The step between two numbered graduations. 0 = chosen by the scale: a nice step (1, 2, 2.5 or 5 times a power of ten, then 3, 4.5 or 6) that falls on both ends when one does — 0 to 90 by 10, −50 to 50 by 25, 0 to 360 by 60 —, otherwise counted from the minimum (32 to 212 by 20). A step you give is always counted from the minimum; a step that would draw more than 200 graduations falls back on the automatic one. Each end carries a numbered graduation. When the numbers do not all fit, one in k is written so the step stays regular, and both ends are always written. The numbers take the decimals of their step. The step chosen is never finer than what is_format writes (0 to 3 at #,##0: 0, 1, 2, 3); a step you give stays yours, and the format rounds its numbers. On a dial too small for a circle of numbers none is written; on a small filled arc the readout moves to keep both ends |
ii_minor_ticks | integer | 4 | Small graduations between two numbered ones (0 to 9) |
ib_show_ticks | boolean | true | Shows the graduations |
ib_show_labels | boolean | true | Shows the numbers of the scale; on a dial too small for a circle of numbers none is written — the readout and the ranges still speak |
id_target | double | 0 | A target — a goal, a threshold —, marked across the band while ib_show_target is true |
ib_show_target | boolean | false | Shows the mark of id_target |
is_pointer | string | needle | How the value is shown (constants POINTER_*): NEEDLE, a needle; BAR, the band filled from the minimum — a solid gauge, the number in the middle; MARKER, a triangle on the rim. Unknown = NEEDLE |
il_value_color | long | -1 | The colour of the value — the needle, the filled arc or the marker; -1 = the theme accent |
il_track_color | long | -1 | The colour of the band; -1 = a tint of the text colour of the theme |
ii_thickness | integer | 0 | The thickness of the band, in pixels (0 to 80, never more than half the radius); 0 = automatic: a share of the radius, kept between 6 and 24 px under a needle or a marker, between 8 and 36 px for a filled arc — a large dial stays a dial. The numbers of the scale (11 to 16 px) and the readout grow with it |
ib_reversed | boolean | false | The maximum at the start of the arc: the scale runs counter-clockwise. Right and Up still turn clockwise: on a reversed dial they lower the value |
ii_start_angle | integer | -135 | Where the scale starts, in degrees: 0 at the top, 90 on the right, -90 on the left (450 reads back 90) |
ii_sweep_angle | integer | 270 | How much of the circle the scale covers, in degrees (10 to 360). A negative angle counts as its size: to make the scale run the other way, ib_reversed. The dial is fitted to the room that angle takes |
ib_editable | boolean | false | The user moves the value: turn the needle round the pivot, click the dial, arrows, Page Up / Down (ten steps), Home and End. A click near the pivot, on the readout or away from the dial (beyond the band and the marks beside it) sets nothing; during a drag the hand may leave the dial, the value stays at the end it comes from and never jumps across the gap. Right and Up turn clockwise, as a rotary knob, wherever the arc runs (on a reversed dial they lower the value). Each gesture raises ue_value_changed once — a key, like the hand, puts the value at once, and a drag cut short (a message box, Alt+Tab) ends like a release; Escape during a drag gives the value back (a value your code wrote meanwhile stays) without pressing the window's Cancel button; the Menu key names the range the value is in |
id_step | double | 0 | The step of the hand and of the keys; 0 = the precision the readout shows (the decimals of is_format, or those the scale chooses): on a scale of 0 to 7 the hand gives 2.6, never a 2.61 the user did not read; a key moves by a hundredth of the scale, never less than one shown digit. Both ends stay reachable when the step does not divide the scale: from 0 to 100 by 30, the value goes 0, 30, 60, 90, 100 |
ib_track_drag | boolean | false | With ib_editable, opt-in: while the user drags the value, ue_value_tracking follows the hand — a volume heard live, a preview redrawn. ue_value_changed still comes once, when the hand lets go; when a drag is cut short (Escape, ib_editable or ib_enabled set to false by the code), ue_value_tracking also says the value it started from |
ib_value_tooltip | boolean | true | The panel that names the range under the pointer, with its ends. It is not is_tooltip, the tooltip of the whole component. The tooltip of a range (its is_tooltip) is written in this panel, even at false |
ib_value_follows_range | boolean | false | Opt-in: the value — the needle, the filled arc or the marker — takes the colour of the range it is in (the one drawn on top where two overlap): red in the red zone. Outside every range it keeps il_value_color, else the theme accent. While the value slides, the colour follows the value drawn |
ib_rounded | boolean | false | Opt-in: round ends on the band, the filled arc and the ranges. Each one is shortened by half its width at both ends so that it stays on its part of the scale; a range shorter than its own width becomes a dot. A full circle keeps its band closed |
ib_pointer_tooltip | boolean | false | Opt-in: the panel also names the value under the mouse — on the needle, the filled arc or the marker — and the target, with their number in the format of the readout. The ranges keep their own panel (ib_value_tooltip) |
id_origin | double | 0 | Where the filled arc (POINTER_BAR) starts: a value below the origin fills the other way — a gap, a variance, a scale of −50 to 50 that starts at 0. Until it is set — or once set back to NULL — the arc starts at the minimum and the property reads the minimum; outside the scale, at the nearest end. The twin of id_origin of gauge |
ib_auto_height | boolean | false | The component reports its ideal height and the userobject fits it (ue_auto_height). The width drives it: a half dial is half as tall |
ib_enabled | boolean | true | Greyed out, it keeps showing its value but stops answering: no click, no key, no drag, and it leaves the Tab order |
ib_animated | boolean | true | The value slides to its place, frame by frame — the needle turns —, and arrives from the start of the scale (its minimum) when the component is drawn. A setting changed during the slide (title, unit, colour, size) does not cut it. A workstation set to reduce motion never animates; the user's hand is never animated; a value set under of_set_redraw(false) slides when drawing resumes |
ii_anim_duration | integer | 450 | Duration of the slide, in milliseconds (0 to 5000) |
is_anim_easing | string | ease-out | The curve of the slide (constants EASING_*, the names of LiveCharts2): back-out goes past then comes back, bounce-out bounces, elastic-out snaps. An overshoot stays on the scale. Unknown = ease-out |
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 theme's accent) |
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 | "" | Text of the rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the rich tooltip |
Methods #
| Method | Role | |
|---|---|---|
of_add_range ( string as_key, double ad_from, double ad_to { , long al_color } ) | Adds a coloured range from ad_from to ad_to (ends written backwards are drawn the right way round); the overload with a colour sets it, otherwise the tone then the palette. Returns 0 once added, -5 when the key is empty, holds / or ` | , or is already held (an add never replaces), -2` when the component is not created. The palette colour is given at the add: removing a range recolours no other one |
of_clear_ranges ( ) | Removes every range — their handles go with them —, the value and the settings stay. Returns 0 once done, -2 when the component is not created | |
of_current_range ( ) | The key of the range the value is in right now, an empty string when it is in none or when the scale is empty. Where two ranges overlap, the last one added — the one drawn on top — wins. A hidden range is not counted; a range the demo mode does not draw is: what this reads never depends on the licence. A range holds its start but not its end: on the end two ranges share, the value is in the one that starts there, whatever the order of the adds; the end of the scale belongs to the range that reaches it. A range outside the scale (not drawn) counts too | |
of_range ( string as_key ) | The n_pbt_angulargauge_range handle of a range, to read or change its ends, colour, tone, name or visibility | |
of_remove_range ( string as_key ) | Removes one range; its handle is destroyed. Returns 0 once removed, -5 when no range has this key, -2 when the component is not created | |
of_reset ( ) | Empties the ranges — handles included — and puts every property back to its original value. Returns 0 once done, -2 when the component is not created |
Events #
| Event | Raised when |
|---|---|
ue_value_changed (double ad_value) | With ib_editable only: the user has moved the value — once per drag (when the button is released, or when the drag is cut short: a message box opened under the hand, Alt+Tab), per click, per key. A value set by your code does not raise it, even during a drag. To follow the hand during the drag: ib_track_drag |
ue_value_tracking (double ad_value) | With ib_editable and ib_track_drag only, while the user drags the value: each new place of the hand, then — when the drag is cut short: Escape, or ib_editable / ib_enabled set to false by your code — the value it started from. The final value still comes once in ue_value_changed |
ue_range_clicked (string as_key) | A range was clicked — or confirmed with Enter or Space on the range the keyboard is on (Tab, then the arrows). Not on an editable component: a click there sets the value |
ue_range_rclicked (string as_key, long al_x, long al_y) | Right-click on a range, or the Menu key (Shift+F10) on the range the keyboard is on — on an editable component, the range the value is in: the place to open a menu; al_x, al_y: where to open the menu, in screen pixels — the pointer, or the middle of the range from the keyboard (Menu key, Shift+F10); a contextmenu opens there as they are (uo_menu.of_show(al_x, al_y)) |
ue_auto_height (long al_height) | With ib_auto_height: the userobject has just been resized to its ideal height |
Item properties #
A range is named by its key: uo_dial.of_range("warn").is_tone = u_pbt_angulargauge.TONE_WARN.
| Property | Type | Default | Role |
|---|---|---|---|
id_from | double | 0 | The start of the range, on the scale |
id_to | double | 0 | Its end. Ends written backwards are drawn the right way round and read back as given |
il_color | long | -1 | Its colour; -1 = that of its tone, otherwise of the palette. The inherited item colours (il_accent, il_back_color, il_text_color and their hover twins) have no effect on a range: il_color and is_tone decide |
is_tone | string | "" | Its tone (constants TONE_* of the component): SUCCESS, WARN, DANGER, INFO (the theme accent), NEUTRAL — one set per light or dark mode, any case understood. il_color wins; an unknown tone counts as no tone |
is_label | string | "" | Its name, in the panel under the pointer and for a screen reader; empty = its key. Markup accepted |
ib_visible | boolean | true | Hides the range without removing it; like a check box, raises no event |
is_tooltip | string | "" | Its tooltip, written in the panel that names the range under the pointer — never a second bubble. Markup accepted |
is_super_tooltip_title | string | "" | The bold title of its tooltip, written in the panel under its name |
is_super_tooltip_text | string | "" | The text of its tooltip, in the panel. Markup accepted |
is_super_tooltip_image | string | "" | An image at the top of its tooltip, in the panel (bundle path, absolute path or resources.dll:name) |
Examples #
A live dashboard #
// Timer event of the window : the needle turns to each new reading
uo_dial.id_value = ids_monitor.GetItemNumber(1, "speed")
// Which range is it in now ? An alert outside the good one
st_alert.visible = (uo_dial.of_current_range() <> "city")
A solid half gauge #
// The band fills from the minimum, the number in the middle
uo_dial.is_pointer = u_pbt_angulargauge.POINTER_BAR
// From the left, over half a circle : the upper half
uo_dial.ii_start_angle = -90
uo_dial.ii_sweep_angle = 180
// A scale from 0 to 1, written as a percentage
uo_dial.id_maximum = 1
uo_dial.is_format = "0%"
uo_dial.id_value = 0.72
A gap around zero #
// A scale centred on zero : the filled arc starts at 0, not at the minimum
uo_dial.is_pointer = u_pbt_angulargauge.POINTER_BAR
uo_dial.id_minimum = -50
uo_dial.id_maximum = 50
uo_dial.id_origin = 0
// Below the budget, the arc fills to the left of 0
uo_dial.id_value = -18
A value the user sets #
// The user moves the value, by steps of 5
uo_dial.ib_editable = true
uo_dial.id_step = 5
// Event ue_value_changed of uo_dial : apply what the user chose
ii_level = Integer(ad_value)
A volume set live #
// The user drags the value, and the sound follows the hand
uo_dial.ib_editable = true
uo_dial.ib_track_drag = true
// Event ue_value_tracking of uo_dial : the volume heard while the hand moves
inv_player.ii_volume = Integer(ad_value)
// Event ue_value_changed of uo_dial : the volume kept when the hand lets go
ii_saved_volume = Integer(ad_value)
A modern KPI #
// A filled arc with round ends, in the colour of the zone it is in
uo_dial.is_pointer = u_pbt_angulargauge.POINTER_BAR
uo_dial.ib_rounded = true
uo_dial.ib_value_follows_range = true
// The goal, and its number under the mouse
uo_dial.id_target = 85
uo_dial.ib_show_target = true
uo_dial.ib_pointer_tooltip = true
uo_dial.id_value = 74
A menu on a range #
// Event ue_range_rclicked of uo_dial : remember the range, then open the menu
// at the pointer of the window
is_menu_range = as_key
m_range.PopMenu(/*xlocation*/ w_main.PointerX(), /*ylocation*/ w_main.PointerY())
A picture of the dial for a report #
// The dial as it is on screen, title and readout included, to a PNG file
uo_dial.of_save_as_png(/*path*/ "C:\Reports\speed.png")
// The same, printed into a PDF file without any dialog
uo_dial.of_print_to_pdf(/*path*/ "C:\Reports\speed.pdf")
Good practice #
- Three ranges at most, with their tones: good, careful, bad. Beyond that, the eye no longer reads the colour under the needle.
- A format rather than a calculation:
0%on a scale of 0 to 1,$#,##0for money — the value stays the code's. - On a dashboard that refreshes often, keep the animation: the value slides from where it is, it does not start over.
- A colour that means something is set through the tone; leave the value to the theme accent, it follows the light or dark theme.
- For a report, the picture of the dial as it is on screen comes from the base:
of_save_as_png(orof_save_as_jpg),of_print_to_pdf,of_print— the final value, never a needle half way.
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 |
is_accessible_name · is_accessible_description | The name and description a screen reader says | 3.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.