# listbar — `u_pbt_listbar` #

← Komponentenreferenz · Inhalt des Handbuchs

> Seitliche Navigationsleiste: einklappbare Abschnitte im Akkordeon-Stil, die Einträge mit Symbol enthalten, mit einem Akzentband auf dem aktuellen Eintrag und dem Einklappen zu einer Symbolleiste.

> ▶ Live ansehen — Demoanwendung, Kachel Listbar: die Vorschau, der zugehörige Code und diese Seite, nebeneinander.

## Auf einen Blick #

Userobject | `u_pbt_listbar`
Item-Klassen | `n_pbt_listbar_section` (Abschnitt) → `n_pbt_listbar_item` (Eintrag)
Wofür | Ein aus Schaltflächen zusammengebasteltes Seitenmenü durch eine strukturierte, gestaltete und einklappbare Navigation ersetzen
Opt-in-Optionen | `ib_auto_width`, `ib_reorderable`

Dies ist die einzige Komponente der Bibliothek, die `ib_auto_width` veröffentlicht: Ihre natürliche Breite hat tatsächlich eine Bedeutung, da die eingeklappte Leiste deutlich schmaler ist als die ausgeklappte Leiste. Der übliche Fall ist im Übrigen bereits abgedeckt, ohne dass etwas zu aktivieren wäre — `ib_collapsed = true` verkleinert die Leiste auf die Symbolleiste und gibt ihr die Breite beim Ausklappen zurück.

## Schnellstart #

    // open-Event des Fensters
    n_pbt_listbar_section lnv_section

    lnv_section = uo_nav.of_add_header(/*id*/ "nav", /*titel*/ "Navigation")
    lnv_section.of_add_item(/*id*/ "accueil",   /*beschriftung*/ "Startseite",   /*symbol*/ "mono:img\home.svg")
    lnv_section.of_add_item(/*id*/ "documents", /*beschriftung*/ "Dokumente", /*symbol*/ "mono:img\doc.svg")
    lnv_section.of_add_item(/*id*/ "recherche", /*beschriftung*/ "Suche", /*symbol*/ "mono:img\find.svg")

    uo_nav.of_add_header(/*id*/ "config", /*titel*/ "Einstellungen") &
          .of_add_item(/*id*/ "preferences", /*beschriftung*/ "Voreinstellungen", /*symbol*/ "mono:img\gear.svg")

    // Die Auswahl wird auf dem EINTRAG gesetzt, ueber seinen vollstaendigen Pfad
    uo_nav.of_select_item("nav", "accueil")

    // Event ue_selection_changed von uo_nav : (string as_from_section, string as_from_id,
    //                                          string as_section, string as_id)
    choose case as_section + "/" + as_id
        case "nav/accueil"       ; of_ouvrir_accueil()
        case "nav/documents"     ; of_ouvrir_documents()
        case "config/preferences"; of_ouvrir_preferences()
    end choose

## Zwei Ebenen, ein zwingender Pfad #

Ein Eintragsbezeichner ist nur innerhalb seines Abschnitts eindeutig: Es gibt daher keine Abkürzung zum Eintrag. Jeder Zugriff führt über den Abschnitt, was die Schreibweise eindeutig macht — siehe Hierarchien.

    // Komponente  ->  Abschnitt      ->  Eintrag     ->  Eigenschaft
    uo_nav        .of_section("nav") .of_item("docs") .is_text = "Documents"

Auch die Events tragen den vollständigen Pfad, und den verlassenen Eintrag dazu: `ue_selection_changed(as_from_section, as_from_id, as_section, as_id)`.

## Eigenschaften #

Eigenschaft | Typ | Standard | Zweck
--- | --- | --- | ---
`ib_collapsed` | boolean | `false` | `true` klappt die Leiste zu einer Symbolleiste ein: Die Beschriftungen verschwinden, die Symbole bleiben anklickbar
`ib_auto_width` | boolean | `false` | Opt-in: dasselbe für die Breite, auch im ausgeklappten Zustand (die Leiste richtet sich nach der längsten Beschriftung). Das Einklappen zur Symbolleiste schrumpft dagegen bereits von selbst; `ue_auto_width` folgt in beiden Fällen
`ib_reorderable` | boolean | `false` | Opt-in: Der Benutzer kann einen Eintrag mit der Maus verschieben. Die Bewegung bleibt innerhalb seines Abschnitts — eine Eintrags-Kennung ist nur dort eindeutig, ein Wechsel brächte also das Risiko zweier gleicher Schlüssel (löst `ue_item_reordered` aus)
`ib_veto_selection` | boolean | `true` | Nachfragen, bevor die Auswahl umspringt (löst `ue_selection_changing` aus, das ablehnen kann). Standardmäßig aktiv: Wird nichts geskriptet, ist der Wechsel immer erlaubt. Auf `false` setzen, um den Hin- und Rückweg zu PowerBuilder (~35 ms) dort zu sparen, wo er auffiele — Tastaturnavigation, in einer Schleife verschobene Auswahl
`is_theme_style` | string | `fluent` | Visueller Stil der Komponente (Konstanten `THEME_STYLE_*`)
`is_theme_mode` | string | `light` | Helle oder dunkle Variante (Konstanten `THEME_MODE_*`)
`il_theme_accent` | long | `-1` | Akzentfarbe dieser Komponente (`-1` = Akzent des Designs)
`is_tooltip` | string | `""` | Einfacher Tooltip beim Überfahren der Komponente
`is_super_tooltip_title` | string | `""` | Titel des erweiterten Tooltips (hat Vorrang vor `is_tooltip`)
`is_super_tooltip_text` | string | `""` | Text des erweiterten Tooltips (Rich-Markup zulässig)
`is_super_tooltip_image` | string | `""` | Bild des erweiterten Tooltips

### Eigenschaften eines Abschnitts — `n_pbt_listbar_section` #

Eigenschaft | Typ | Standard | Zweck
--- | --- | --- | ---
`is_title` | string | `""` | Titel des Abschnitts. Akzeptiert die Rich-Text-Auszeichnung. Ein leerer Titel zeigt gar keine Kopfzeile an: Der Abschnitt wird zu einer einfachen, unsichtbaren Gruppierung
`ib_collapsed` | boolean | `false` | Akkordeon: `true` klappt die Einträge dieses Abschnitts ein. Die Kopfzeile bleibt sichtbar, ihr Chevron dreht sich

### Eigenschaften eines Eintrags — `n_pbt_listbar_item` #

Eigenschaft | Typ | Standard | Zweck
--- | --- | --- | ---
`is_text` | string | `""` | Beschriftung des Eintrags, im laufenden Betrieb änderbar, ohne die Leiste neu aufzubauen. Akzeptiert die Rich-Text-Auszeichnung
`is_image` | string | `""` | Symbol, im laufenden Betrieb änderbar (akzeptierte Formen: Pfad, `mono:`, `tint:`, DLL-Ressource)
`ib_enabled` | boolean | `true` | `false` graut den Eintrag aus und blockiert seinen Klick
`ib_visible` | boolean | `true` | `false` blendet den Eintrag aus, ohne ihn aus der Leiste zu entfernen
`is_tooltip` | string | `""` | Einfacher Tooltip beim Überfahren des Items
`is_super_tooltip_title` | string | `""` | Titel des erweiterten Item-Tooltips (hat Vorrang vor `is_tooltip`)
`is_super_tooltip_text` | string | `""` | Text des erweiterten Item-Tooltips (Rich-Markup zulässig)
`is_super_tooltip_image` | string | `""` | Bild des erweiterten Item-Tooltips

## Methoden #

### Auf der Komponente #

Methode | Zweck
--- | ---
`of_add_header (string as_id, string as_text)` | Fügt einen Abschnitt hinzu und gibt sein Handle `n_pbt_listbar_section` zurück, an dem sich die Einträge anfügen lassen
`of_section (string as_id)` | Handle eines vorhandenen Abschnitts (beim ersten Zugriff erzeugt)
`of_insert_item (string as_section, string as_id, string as_text, integer ai_index)` | Fügt einen Eintrag an der Position `ai_index` innerhalb seines Abschnitts ein
`of_insert_item (string as_section, string as_id, string as_text, string as_image, integer ai_index)` | Ebenso, mit dem Symbol des Eintrags: `of_add_item` nimmt eines entgegen, also muss auch das Einfügen eines annehmen können
`of_move_item (string as_section, string as_id, integer ai_index)` | Verschiebt einen vorhandenen Eintrag innerhalb seines Abschnitts und behält dabei seinen Zustand bei
`of_remove_item (string as_section, string as_id)` | Entfernt einen Eintrag, bezeichnet durch sein Paar Abschnitt / Bezeichner
`of_clear ( )` | Leert die Leiste: alle Abschnitte und alle Einträge
`of_select_item (string as_section, string as_id)` | Wählt einen Eintrag aus — exakt gleichbedeutend mit einem Klick des Benutzers: `ue_selection_changing` wird zuerst gefragt, dann meldet `ue_selection_changed` den Wechsel
`of_get_layout ( )` | Liest die aktuelle Anordnung als JSON zurück: die Abschnitte in ihrer Reihenfolge, jeder mit seinen Einträgen in Reihenfolge und dem Zustand eingeklappt. Speichern (Datei, Datenbank, Registry) und beim nächsten Start mit `of_set_layout` zurückgeben. Dasselbe Paar trägt auf jeder umsortierbaren Komponente dieselben Namen
`of_set_layout (string as_layout_json)` | Stellt eine mit `of_get_layout` gelesene oder über `ue_layout_changed` empfangene Anordnung wieder her. Was die Anordnung nicht nennt, behält seinen Platz am Ende: Eine gestern gespeicherte Anordnung darf seither Hinzugefügtes nicht verschwinden lassen. Das Anwenden löst kein Event aus — Sie haben sie geliefert
`of_clear_selection ( )` | Lässt keinen Eintrag ausgewählt. Wird wie jeder andere Wechsel gemeldet
`of_selected_key ( )` | Bezeichner des ausgewählten Eintrags, `""` wenn keiner ausgewählt ist. Immer der aktuelle: ein Klick und `of_select_item` laufen beide über `ue_selection_changed`
`of_selected_section ( )` | Abschnitt, der den ausgewählten Eintrag enthält — eine Eintrags-Id ist nur innerhalb ihres Abschnitts eindeutig, das Paar bezeichnet also die Auswahl. `""` wenn keiner
`of_reset ( )` | Leert die Leiste und bringt die Komponente anschließend in ihren Neuzustand zurück
`of_set_redraw (boolean)` | Fasst eine Folge von Änderungen zu einer einzigen Darstellung zusammen
`of_save_as_png (string)` · `of_save_as_jpg (string)` | Exportiert die Darstellung als Bild

### Auf einem Abschnitt — `n_pbt_listbar_section` #

Methode | Zweck
--- | ---
`of_add_item (string as_id, string as_label, string as_icon_file)` | Fügt diesem Abschnitt einen normalen Eintrag hinzu und gibt sein Handle zurück
`of_item (string as_id)` | Handle eines Eintrags dieses Abschnitts (beim ersten Zugriff erzeugt)

## Events #

Event | Ausgelöst wenn
--- | ---
`ue_selection_changed (string as_from_section, string as_from_id, string as_section, string as_id)` | Die Auswahl ist umgesprungen — durch Klick oder über `of_select_item`. Dieselben Argumente wie `ue_selection_changing`: Frage und Ergebnis lesen sich gleich, und das Paar `as_from_*` bezeichnet den verlassenen Eintrag (leer, wenn es keinen gibt)
`ue_section_toggled (string as_section, boolean ab_collapsed)` | Der Benutzer klappt einen Abschnitt über dessen Kopfzeile ein oder aus
`ue_item_reordered (string as_section, string as_id, integer ai_index)` | Der Benutzer hat das Ziehen eines Eintrags beendet. `ai_index` ist sein neuer Rang innerhalb seines Abschnitts, ab 1. Bewahren Sie diese Reihenfolge auf, um dem Benutzer seine Leiste so zurückzugeben, wie er sie verlassen hat
`ue_layout_changed (string as_layout_json)` | Die Anordnung hat sich geändert — der Benutzer hat etwas umsortiert, oder Ihr eigener Code. Trägt die gesamte Anordnung, nicht nur das Verschobene: Das Speichern ist eine einzige Zuweisung
`ue_selection_changing (string as_from_section, string as_from_id, string as_section, string as_id)` → boolean | Abbrechbar, wird vor dem Umspringen der Auswahl gestellt. Standardmäßig ausgelöst; `ib_veto_selection = false` entfernt sie. Geben Sie `false` zurück, um den Benutzer dort zu halten, wo er ist
`ue_auto_width (long al_width)` | Die Komponente hat ihre ideale Breite neu berechnet — erfordert `ib_auto_width = true`
`ue_ready ( )` | Die Komponente ist fertig geladen; alles zuvor Gesendete wurde nachgespielt
`ue_runtime_missing ( )` | Die WebView2-Runtime fehlt: die Komponente bleibt leer
`ue_bg_color (long al_color)` | Die Komponente hat ihre Design-Hintergrundfarbe berechnet; das Userobject hat sie bereits übernommen (`backcolor`)

## Beispiele #

### Vollständiges Seitenmenü #

    n_pbt_listbar_section lnv_dossiers, lnv_outils

    uo_nav.of_set_redraw(false)

    lnv_dossiers = uo_nav.of_add_header("dossiers", "Ordner")
    lnv_dossiers.of_add_item("recents",  "Zuletzt verwendet",  "mono:img\clock.svg")
    lnv_dossiers.of_add_item("clients",  "Kunden",  "mono:img\user.svg")
    lnv_dossiers.of_add_item("archives", "Archiv", "mono:img\box.svg")

    lnv_outils = uo_nav.of_add_header("outils", "Werkzeuge")
    lnv_outils.of_add_item("import", "Importieren", "mono:img\import.svg")
    lnv_outils.of_add_item("export", "Exportieren", "mono:img\export.svg")

    uo_nav.of_set_redraw(true)
    uo_nav.of_select_item("dossiers", "recents")

### Einklappbare Leiste, die Platz freigibt #

    // Zur Symbolleiste einklappen : die Leiste schrumpft von selbst (und nimmt ihre
    // Breite wieder an, wenn Sie sie ausklappen).
    uo_nav.ib_collapsed = true

    // Event ue_auto_width von uo_nav : (long al_width)
    // Die Leiste hat gerade ihre ideale Breite angenommen : was rechts davon liegt, neu ausrichten.
    uo_contenu.x     = uo_nav.x + al_width
    uo_contenu.width = parent.width - uo_contenu.x

### Akkordeon: einen Abschnitt einklappen #

    // Den selten benutzten Archiv-Abschnitt einklappen
    uo_nav.of_section("archives").ib_collapsed = true

    // Event ue_section_toggled von uo_nav : (string as_section, boolean ab_collapsed)
    of_enregistrer_preference("section_" + as_section, String(ab_collapsed))

### Auf die Navigation reagieren #

    // Event ue_selection_changed von uo_nav : (string as_from_section, string as_from_id,
    //                                          string as_section, string as_id)
    // Der Abschnitt ist Teil des Schluessels : zwei Abschnitte koennen beide einen Eintrag "liste" haben.
    choose case as_section
        case "dossiers" ; of_ouvrir_dossier(as_id)
        case "outils"   ; of_lancer_outil(as_id)
    end choose

### Einen Auswahlwechsel ablehnen #

    // Die Frage wird STANDARDMAESSIG gestellt: nichts zu aktivieren. Diese Zeile tut
    // das Gegenteil und entfernt sie, wo die Abwaegung nichts bringt und kostet.
    uo_nav.ib_veto_selection = false

    // Event ue_selection_changing von uo_nav :
    //   (string as_from_section, string as_from_id, string as_section, string as_id)
    // FALSE zurueckzugeben haelt den Benutzer auf dem Eintrag, den er verlaesst.
    if of_saisie_en_cours(as_from_section, as_from_id) then
        MessageBox("Eingabe", "Schließen Sie die laufende Akte ab, bevor Sie navigieren.")
        return false
    end if
    return true

### Einen Eintrag im laufenden Betrieb aktualisieren #

    n_pbt_listbar_item lnv_entree

    // Der vollstaendige Pfad ist zwingend : Komponente -> Abschnitt -> Eintrag
    lnv_entree = uo_nav.of_section("dossiers").of_item("recents")
    lnv_entree.is_text  = "Zuletzt verwendet (12)"
    lnv_entree.is_image = "mono:img\clock_full.svg"

    // Je nach Berechtigungen ausgrauen oder ausblenden, ohne die Leiste neu aufzubauen
    uo_nav.of_section("outils").of_item("import").ib_enabled = of_a_le_droit("import")
    uo_nav.of_section("outils").of_item("export").ib_visible = gb_mode_expert

### Auswahl aus dem Code gesteuert #

    // Die Auswahl woanders setzen : das Akzentband folgt
    uo_nav.of_select_item("dossiers", "clients")

    // Oder sie vollstaendig loeschen
    uo_nav.of_clear_selection()

### Die Leiste neu aufbauen #

    // of_clear leert Abschnitte und Eintraege ; of_reset stellt zusaetzlich die Standardwerte der Komponente wieder her
    uo_nav.of_clear()
    of_construire_menu_selon_profil()

## Best Practices #

- Bewahren Sie das von `of_add_header` zurückgegebene Abschnitts-Handle in einer lokalen Variablen auf: Das ist besser lesbar, als für jeden Eintrag erneut `of_section(...)` aufzurufen.
- Verwenden Sie `mono:` für die Symbole: Sie werden mit dem Design umgefärbt, hell wie dunkel, und bleiben lesbar, sobald die Leiste zur Symbolleiste eingeklappt ist.
- Ein leerer Abschnittstitel dient als dezente Gruppierung: Die Einträge stehen weiter auseinander, ohne dass eine Kopfzeile erscheint.
- `ib_collapsed` verkleinert das Userobject auf die Symbolleiste, verschiebt aber Ihre anderen Steuerelemente nicht: Behandeln Sie `ue_auto_width`, um den frei gewordenen Platz zu nutzen, sonst bleibt er leer.
- Im Leistenmodus bleiben nur die Symbole übrig: Hinterlegen Sie auf jedem Eintrag einen Tooltip, damit die Beschriftungen weiterhin zugänglich bleiben.
- Die Frage wird standardmäßig gestellt: Ein leer gelassenes `ue_selection_changing` erlaubt den Wechsel immer, Sie müssen nichts tun. Schalten Sie sie mit `ib_veto_selection = false` dort ab, wo wiederholt geklickt wird — Tastaturnavigation, in einer Schleife gesteuerte Auswahl —, denn jede Frage kostet einen Hin- und Rückweg zu PowerBuilder.
- `ib_enabled = false` ist `ib_visible = false` vorzuziehen, wenn der Eintrag wieder verfügbar wird: Das Menü ändert dann nicht vor den Augen des Benutzers seine Form.

← Komponentenreferenz · Inhalt des Handbuchs