# tab — `u_pbt_tab` #

← Komponentenreferenz · Inhalt des Handbuchs

> Moderne Registerkarten, die echte PowerBuilder-Steuerelemente hosten: verschiebbare Registerleiste, Symbole je Registerkarte, schließbare Registerkarten, Umsortieren mit der Maus.

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

## Auf einen Blick #

Userobject | `u_pbt_tab`
Item-Klasse | `n_pbt_tab_page` (eine Seite = eine Registerkarte)
Wofür | Eine PowerBuilder-`tab` durch eine gestaltete Leiste ersetzen und dabei Ihre vorhandenen Masken als Seiten beibehalten
Opt-in-Optionen | `ib_reorderable`

Der entscheidende Punkt: Eine Seite ist kein HTML-Entwurf, sondern ein PowerBuilder-`dragobject` — ein Userobject, eine DataWindow, eine Gruppe von Steuerelementen oder sogar eine weitere PBToolboxAI-Komponente. Die Komponente übernimmt das Positionieren, das Anpassen der Größe sowie das Ein- und Ausblenden beim Wechsel der Registerkarte. Siehe Echte PowerBuilder-Steuerelemente hosten.

## Schnellstart #

    // open-Event des Fensters : jede Seite ist ein PB-Steuerelement, das bereits auf dem Fenster liegt
    uo_onglets.of_add_page("clients",  "Kunden",  uo_page_clients)
    uo_onglets.of_add_page("factures", "Rechnungen", uo_page_factures, /*schliessbar*/ true)

    // Ein Symbol je Registerkarte, am Handle der Seite gesetzt
    uo_onglets.of_item("clients").is_icon  = "mono:img\clients.svg"
    uo_onglets.of_item("factures").is_icon = "mono:img\invoice.svg"

    uo_onglets.of_select_page("clients")

    // Event ue_selection_changed von uo_onglets : (string as_from_id, string as_id)
    of_charger_page(as_id)

## Eigenschaften #

Eigenschaft | Typ | Standard | Zweck
--- | --- | --- | ---
`is_position` | string | `"top"` | Platzierung der Leiste: `top`, `bottom` (waagerechte Leiste), `start`, `end` (senkrechte Leiste). Konstanten `POSITION_TOP`, `POSITION_BOTTOM`, `POSITION_START`, `POSITION_END`. `START`/`END` sind logisch und folgen der Schreibrichtung
`is_overflow_mode` | string | `"menu"` | Was eine für ihre Registerkarten zu kleine Leiste tut. `menu` (Standard) hält jede Registerkarte lesbar: Was nicht mehr hineinpasst, verlässt die Leiste, und die Schaltfläche `···` listet alle auf, wobei die aktive stets sichtbar bleibt. `compact` behält alle in der Leiste und lässt sie schrumpfen, bis auf den Platz, den ein abgeschnittener Text braucht. Konstanten `OVERFLOW_MENU`, `OVERFLOW_COMPACT`
`ib_reorderable` | boolean | `false` | Opt-in: Der Benutzer kann die Registerkarten umsortieren, indem er ihre Kopfzeile mit der Maus zieht (löst `ue_tab_reordered` aus)
`ib_veto_selection` | boolean | `true` | Nachfragen, bevor die aktive Registerkarte wechselt (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
`ib_veto_close` | boolean | `true` | Nachfragen, bevor eine schließbare Registerkarte geschlossen wird (löst `ue_tab_closing` aus, das ablehnen kann). Standardmäßig aktiv, dieselbe Regel
`ib_context_menu` | boolean | `true` | Integriertes Kontextmenü auf einer Registerkarten-Kopfzeile: Schließen, Andere schließen, Rechts davon schließen, Alle schließen, ausgegraut, wenn sie kein Ziel haben. Standardmäßig aktiv. Der Rechtsklick wählt zuerst die Registerkarte aus: Lehnt die Anwendung den Wechsel ab, öffnet sich kein Menü. Jedes Schließen läuft über `ue_tab_closing`, eine Frage pro Seite: die Seite mit ungespeicherter Arbeit lehnt allein ab und bleibt offen, während ihre Nachbarn gehen. Auf `false`, um Ihr eigenes Menü aus `ue_rclicked` anzuzeigen
`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 einer Seite — `n_pbt_tab_page` #

Über `of_item(id)` bezogen, lassen sie sich im laufenden Betrieb ändern, ohne die Leiste neu aufzubauen.

Eigenschaft | Typ | Standard | Zweck
--- | --- | --- | ---
`is_title` | string | `""` | Beschriftung der Registerkarte. Akzeptiert die Rich-Text-Auszeichnung
`is_icon` | string | `""` | Symbol der Registerkarte (zulässige Formen: Pfad, `mono:`, `tint:`, DLL-Ressource). Leer = kein Symbol
`ib_enabled` | boolean | `true` | `false` blendet die Registerkarte grau aus und verhindert ihre Auswahl durch den Benutzer
`ib_visible` | boolean | `true` | `false` blendet die Registerkarte aus, ohne die Seite zu entfernen; wird die aktive Registerkarte ausgeblendet, wird eine benachbarte aktiviert
`ib_closable` | boolean | `false` | Schliesskreuz auf dieser Registerkarte. Beim Hinzufuegen selten bekannt: Es wird `true`, sobald das enthaltene Dokument gespeichert ist, und `false`, solange darin ein Vorgang laeuft
`is_shortcut` | string | `""` | Tastenkombination, die diese Registerkarte aktiviert: `"Ctrl+2"`, `"Alt+F"`, `"F6"`… Sie antwortet, wo immer der Benutzer im Fenster ist, die eingebettete Seite eingeschlossen — die Kombination hält die DLL, nicht die Registerleiste. So auszuwählen ist ein Klick: `ue_selection_changing` wird gefragt, `ue_selection_changed` folgt. `""` entfernt sie
`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 #

Methode | Zweck
--- | ---
`of_add_page (string as_id, string as_title, dragobject ado_page)` | Fügt eine nicht schließbare Registerkarte ohne Symbol hinzu und hostet das Steuerelement
`of_add_page (string as_id, string as_title, dragobject ado_page, boolean ab_closable)` | Dasselbe, mit Schließkreuz, wenn `ab_closable`
`of_add_page (string as_id, string as_title, dragobject ado_page, boolean ab_closable, string as_icon)` | Dasselbe, mit dem Symbol im selben Aufruf gesetzt (die Registerkarte erscheint von Anfang an vollständig)
`of_insert_page (string as_id, string as_title, dragobject ado_page, integer ai_index)` | Fügt die Seite hinzu und verschiebt sie anschließend an die Position `ai_index`
`of_insert_page (string as_id, string as_title, dragobject ado_page, boolean ab_closable, string as_icon, integer ai_index)` | Ebenso, mit dem, was `of_add_page` sagt: ob der Tab schließbar ist, und sein Symbol
`of_move_page (string as_id, integer ai_index)` | Verschiebt eine vorhandene Registerkarte; ihre gehostete Seite und die Auswahl bleiben erhalten
`of_select_page (string as_id)` | Aktiviert eine Registerkarte — genau gleichwertig zu einem Klick des Benutzers (durchläuft `ue_selection_changing`, dann `ue_selection_changed`)
`of_remove_page (string as_id)` | Entfernt die Registerkarte und gibt das Steuerelement an sein ursprüngliches Fenster zurück, ausgeblendet. Das Steuerelement bleibt nutzbar und kann anderswo gehostet werden
`of_selected_key ( )` | Bezeichner der aktiven Registerkarte, `""`, wenn keine aktiv ist
`of_get_layout ( )` | Liest die aktuelle Anordnung als JSON zurück: die Reihenfolge der Registerkarten und deren Sichtbarkeit. 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_item (string as_id)` | `n_pbt_tab_page`-Handle der Seite (beim ersten Zugriff erzeugt)
`of_refresh_page (string as_id)` | Frischt die Darstellung einer außerhalb des Bildschirms aufgebauten Seite auf, ohne Flackern
`of_relayout ( )` | Veröffentlicht den Seitenbereich erneut, damit das gehostete Steuerelement neu positioniert wird (nützlich nach einer verzögerten Anzeige)
`of_preload_icons (string as_icons[])` | Wärmt beim Start einen Satz Symbole vor: Eine später geöffnete Registerkarte zeigt ihr Symbol sofort
`of_reset ( )` | Leert die Leiste: Jede gehostete Seite wird an ihr ursprüngliches Fenster zurückgegeben, danach kehrt die Komponente 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

> `of_add_page` gibt einen negativen Code zurück, wenn der Bezeichner leer ist, bereits verwendet wird oder wenn das übergebene Steuerelement ungültig ist.

Wenn zu viele Registerkarten offen sind — sie schrumpfen, um in das Band zu passen, aber nie unter eine lesbare Breite: Symbol und Schließkreuz beanspruchen ihren Platz zusätzlich zum Titel, nie auf dessen Kosten. Was nicht mehr hineinpasst, wird aus dem Band genommen, und an dessen Ende erscheint eine Schaltfläche `···`: Sie öffnet die Liste aller sichtbaren Registerkarten, die aktive angehakt, und die Auswahl wechselt dorthin. Die aktive Registerkarte bleibt immer sichtbar. Das Band scrollt nicht — diese Schaltfläche ist der Weg zu den Registerkarten außerhalb des Rahmens. Nichts zu programmieren, das Verhalten ist automatisch.

## Events #

Event | Ausgelöst wenn
--- | ---
`ue_selection_changed (string as_from_id, string as_id)` | Die aktive Registerkarte hat gewechselt — durch Klick oder über `of_select_page`. Dieselben Argumente wie `ue_selection_changing`: Frage und Ergebnis lesen sich gleich, und `as_from_id` ist die verlassene Seite
`ue_tab_closed (string as_id)` | Der Benutzer klickt auf das Kreuz einer schließbaren Registerkarte. Die Registerkarte ist bereits entfernt und die Seite an ihr Fenster zurückgegeben
`ue_tab_reordered (string as_id, integer ai_index)` | Der Benutzer hat das Ziehen einer Kopfzeile beendet. `ai_index` ist die neue Position, beginnend bei 1
`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_id, string as_id)` → boolean | Abbrechbar, wird vor dem Wechsel der aktiven Registerkarte gestellt. Standardmäßig ausgelöst; `ib_veto_selection = false` entfernt sie. Geben Sie `false` zurück, um den Benutzer auf seiner Seite zu halten
`ue_tab_closing (string as_id)` → boolean | Abbrechbar, wird vor dem Schließen einer schließbaren Registerkarte gestellt. Standardmäßig ausgelöst; `ib_veto_close = false` entfernt sie. Benannt als Paar zu `ue_tab_closed`: closing / closed. Geben Sie `false` zurück, um die Registerkarte (und ihre gehostete Seite) offen zu halten
`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 #

### Ein Ordner mit fachlichen Seiten #

    // open-Event : die Seiten-Userobjects liegen bereits auf dem Fenster
    uo_onglets.of_set_redraw(false)

    uo_onglets.of_add_page(/*id*/ "identite", /*titel*/ "Identität",  /*seite*/ uo_identite)
    uo_onglets.of_add_page(/*id*/ "adresses", /*titel*/ "Adressen",  /*seite*/ uo_adresses)
    uo_onglets.of_add_page(/*id*/ "compta",   /*titel*/ "Buchhaltung", /*seite*/ uo_compta)

    uo_onglets.of_item("identite").is_icon = "mono:img\user.svg"
    uo_onglets.of_item("adresses").is_icon = "mono:img\map.svg"
    uo_onglets.of_item("compta").is_icon   = "mono:img\euro.svg"

    uo_onglets.of_set_redraw(true)
    uo_onglets.of_select_page("identite")

### Schließbare Dokumente, bei Bedarf geöffnet #

    // Ein Dokument in einer neuen schliessbaren Registerkarte oeffnen
    uo_onglets.of_add_page(/*id*/ ls_cle, /*titel*/ ls_libelle, /*seite*/ uo_editeur, &
                           /*schliessbar*/ true, /*symbol*/ "mono:img\doc.svg")
    uo_onglets.of_select_page(ls_cle)

    // Event ue_tab_closed von uo_onglets : (string as_id)
    // Die Registerkarte ist bereits entfernt ; es bleibt nur, Ihre Fachdaten freizugeben.
    of_liberer_document(as_id)

### Umsortieren mit der Maus #

    uo_onglets.ib_reorderable = true

    // Event ue_tab_reordered von uo_onglets : (string as_id, integer ai_index)
    // ai_index = neue Position, beginnend bei 1 : wir speichern die gewaehlte Reihenfolge.
    of_enregistrer_ordre(as_id, ai_index)

### Senkrechte Leiste #

    // Registerleiste an der linken Seite, nuetzlich bei langen Beschriftungen
    uo_onglets.is_position = uo_onglets.POSITION_START

### Eine Registerkarte je nach Rechten grau ausblenden oder verbergen #

    // Der Weg fuehrt immer ueber das Handle der Seite
    uo_onglets.of_item("compta").ib_enabled = of_a_le_droit("compta")
    uo_onglets.of_item("audit").ib_visible  = gb_mode_expert

### Auf die Auswahl reagieren #

    // Event ue_selection_changed von uo_onglets : (string as_from_id, string as_id)
    choose case as_id
        case "identite" ; uo_identite.of_rafraichir()
        case "adresses" ; uo_adresses.of_rafraichir()
        case "compta"   ; uo_compta.of_rafraichir()
    end choose

### Einen Registerkartenwechsel oder ein Schließen ablehnen #

    // Beide Fragen werden STANDARDMAESSIG gestellt: nichts zu aktivieren. Diese
    // Zeilen tun das Gegenteil und entfernen sie, wo die Abwaegung nichts bringt.
    uo_onglets.ib_veto_selection = false
    uo_onglets.ib_veto_close     = false

    // Event ue_selection_changing von uo_onglets : (string as_from_id, string as_id)
    // FALSE zurueckzugeben haelt den Benutzer auf der Seite, die er verlaesst.
    if of_page_modifiee(as_from_id) then
        if MessageBox("Änderungen", "Ohne Speichern verlassen?", Question!, YesNo!) = 2 then
            return false
        end if
    end if
    return true

    // Event ue_tab_closing von uo_onglets : (string as_id)
    // FALSE zurueckzugeben haelt die Registerkarte und ihre gehostete Seite offen.
    return not of_page_modifiee(as_id)

### Wieder mit einer leeren Leiste beginnen #

    // of_reset gibt JEDE gehostete Seite an ihr urspruengliches Fenster zurueck, bevor geleert wird
    uo_onglets.of_reset()
    uo_onglets.of_add_page("accueil", "Startseite", uo_accueil)

## Best Practices #

- Die gehosteten Steuerelemente müssen vor dem Aufruf vorhanden sein: Legen Sie sie zur Entwurfszeit auf das Fenster, die Komponente kümmert sich um das Ausblenden und das Neupositionieren.
- Laden Sie die Seiten einmal im `open`-Event und steuern Sie danach nur noch die Auswahl: Das ist schneller, als fortlaufend Seiten hinzuzufügen und zu entfernen.
- Rufen Sie `of_preload_icons` beim Start auf, wenn Ihre Registerkarten Symbole tragen: Andernfalls zeigt sich beim ersten Öffnen einer ausgeblendeten Registerkarte eine kurze Verzögerung, bevor das Symbol erscheint.
- Beide Fragen werden standardmäßig gestellt: Ein leer gelassenes Ereignis erlaubt die Aktion immer, Sie müssen nichts tun. Schalten Sie sie mit `ib_veto_selection` / `ib_veto_close` auf `false` ab, wenn die Abwägung Ihnen nichts bringt, denn jede Frage kostet einen Hin- und Rückweg zu PowerBuilder.
- Ein gehostetes Steuerelement ist ein natives Fenster: Es zeichnet sich über der Web-Ebene. Kein visueller Effekt der Komponente kann darüber hinweggehen.
- Vergessen Sie `of_reset()` nicht, bevor Sie eine Leiste neu aufbauen: Ohne diesen Aufruf schlägt die Wiederverwendung eines Seitenbezeichners fehl und die vorherigen Steuerelemente bleiben sichtbar.
- Für Bereiche, die sich in der Größe ändern und abdocken lassen, statt sich gegenseitig ausschließender Seiten, greifen Sie besser zu dockcontainer.

← Komponentenreferenz · Inhalt des Handbuchs