# 3. Base comune `u_pbt_base` #

← Primi passi · Sommario · Temi →

Tutti i componenti visivi ereditano da `u_pbt_base`, che fornisce il ciclo di vita, il motore delle proprietà, il trasporto verso il componente web e la gestione degli errori. Le proprietà vere e proprie — tema e tooltip compresi — sono pubblicate da ogni componente: la pagina del componente ne riporta l'elenco completo. Non si utilizza mai `u_pbt_base` direttamente — si posiziona un componente concreto — ma tutto quanto segue è disponibile ovunque.

## 3.1 Il motore delle proprietà #

### Assegnare #

Ogni valore pilotabile è una variabile di istanza pubblica, assegnata direttamente:

    uo_progress.id_value   = 42.5
    uo_progress.is_label   = "Importazione in corso…"
    uo_progress.ib_animated = true

Il prefisso ungherese indica il tipo: `is_` string, `ib_` boolean, `ii_` integer, `il_` long (spesso un colore `RGB()`), `id_` double.

Non esiste alcun `of_set_xxx` scalare: una proprietà si imposta per assegnazione. Restano metodi le aggiunte, le rimozioni e le azioni (`of_add_*`, `of_remove_*`, `of_select_*`, `of_reset`, `of_set_layout`…).

### Rileggere #

La lettura restituisce l'ultimo valore impostato (cache sul lato PowerBuilder):

    if uo_progress.id_value >= 100 then …

Un componente web non può essere interrogato in modo sincrono: questa cache viene quindi aggiornata dagli event. Ogni volta che il componente sposta da sé una proprietà — l'utente segue un collegamento, ingrandisce con la rotellina, riduce la barra multifunzione, digita del testo — l'event che vi avvisa aggiorna la proprietà per strada. La rilettura restituisce allora lo stato reale, e il nuovo valore è già presente quando viene eseguito il codice dell'event.

Lo stesso vale per gli item : dopo un clic dell'utente, `of_item(...)` rilegge ciò che è a schermo — la voce selezionata, la sezione ridotta, il pulsante spuntato.

Una proprietà che nessun event accompagna, invece, resta sull'ultimo valore impostato da voi.

### Raggruppare le modifiche #

Una raffica di assegnazioni provoca altrettanti rendering. `of_set_redraw` le fonde in uno solo:

    uo_grid.of_set_redraw(false)
    … venti assegnazioni e of_add_* …
    uo_grid.of_set_redraw(true)     // UN solo ridisegno

Richiamare sempre entrambi (il `true` finale non è facoltativo).

## 3.2 Gli item #

Un componente con contenuto (schede, pulsanti, pannelli, riquadri, sezioni…) espone i propri elementi tramite handle tipizzati, ottenuti dal componente stesso o dal loro elemento padre.

### Aggiungere #

L'aggiunta restituisce l'handle dell'elemento creato:

    n_pbt_tab_page lnv_page

    uo_tab.of_add_page("clients", "Clienti", uo_page_clients)
    lnv_page = uo_tab.of_item("clients")
    lnv_page.is_icon = "img\clients.png"

### Recuperare e modificare #

`of_item(id)` — oppure la factory del livello interessato — restituisce l'handle di un elemento esistente; le sue proprietà si impostano esattamente come quelle di un componente:

    uo_toolbar.of_bar("main").of_item("save").ib_enabled = false
    uo_tab.of_item("clients").is_title = "Clienti (128)"

### Gerarchie: un identificatore è univoco solo all'interno del proprio elemento padre #

Un componente a più livelli non espone alcuna scorciatoia verso la foglia: il percorso completo è obbligatorio, il che garantisce che nessun identificatore sia ambiguo.

    // Barra multifunzione: scheda > gruppo > controllo > voce di menu
    uo_ribbon.of_tab("home").of_group("clipboard").of_item("paste").ib_enabled = false

Anche gli event portano con sé il percorso completo:

    // event ue_clicked di uo_toolbar: (string as_bar, string as_id)
    choose case as_bar + "/" + as_id
        case "main/save" ; of_enregistrer()
    end choose

### Event degli item #

Non esistono event degli item generici sull'antenato: un identificatore di foglia da solo sarebbe ambiguo non appena gli item sono annidati (una toolbar ha più barre, un tilesbox più gruppi…). Ogni componente dichiara quindi i propri event degli item, con il percorso completo: `ue_item_selected (as_section, as_id)` per la listbar, `ue_tile_clicked (as_group, as_id)` per il tilesbox, `ue_clicked (as_bar, as_id)` per la toolbar…

Consultare la pagina del componente: lì si trova l'elenco esatto.

## 3.3 Event comuni a tutti i componenti #

Event | Attivato quando
--- | ---
`ue_ready ( )` | Il componente ha terminato il caricamento; tutto ciò che è stato inviato prima è stato riprodotto
`ue_runtime_missing ( )` | Il runtime WebView2 è assente — vedere Installazione
`ue_bg_color (long al_color)` | Il componente ha calcolato il colore di sfondo del proprio tema; l'userobject ha già adottato questo colore (`backcolor`), spetta a Lei adeguare la finestra se necessario

> I comandi inviati prima di `ue_ready` non vanno perduti: vengono messi in coda e riprodotti nell'ordine. È quindi possibile configurare tutto già nel `constructor` o nell'`open`.

    // event ue_bg_color: adeguare la finestra allo sfondo del componente
    parent.backcolor = al_color

## 3.4 Proprietà ed event opzionali (opt-in) #

Alcune funzionalità non sono attive per impostazione predefinita: vengono pubblicate solo dai componenti in cui hanno un senso ed è necessario richiederle.

### Altezza automatica — `ib_auto_height` #

Il componente misura la propria altezza ideale e ridimensiona l'userobject; l'event `ue_auto_height(al_height)` consente di riposizionare i controlli adiacenti.

    uo_entete.ib_auto_height = true

    // event ue_auto_height di uo_entete
    il_hauteur_entete = al_height
    of_relayout()          // riposiziona il contenuto al di sotto

Pubblicata da: `picture` e `statictext`.

Le bande non pubblicano questa proprietà: la loro altezza è intrinseca. `ribbon` e `toolbar` non scorrono verticalmente: un'altezza fissa può solo produrre spazio vuoto sotto la banda oppure contenuto troncato (barra multifunzione compressa, barra degli strumenti passata su due righe…). Si adattano quindi sempre, senza nulla da attivare, e pubblicano comunque `ue_auto_height` affinché Lei possa riposizionare ciò che si trova al di sotto.

### Larghezza automatica — `ib_auto_width` #

Stesso principio per la larghezza. Pubblicata unicamente da `listbar`, l'unico componente la cui larghezza naturale abbia un senso.

Una listbar compressa in barra di sole icone si restringe da sola e restituisce la larghezza quando viene espansa: `ib_auto_width` Le serve soltanto se desidera seguire anche la larghezza espansa (la barra si allinea allora all'etichetta più lunga).

### Event del mouse ambientali — `ib_track_mouse` #

Gli event del mouse ad alta frequenza sono interrotti alla fonte: senza sottoscrizione, il componente non li emette affatto (nulla attraversa il ponte verso PowerBuilder).

    uo_bouton.ib_track_mouse = true    // attiva ue_mouse_enter / ue_mouse_leave / ue_rclicked

Pubblicati da: `button`, `picture`, `statictext`.

Gli event discreti (clic, selezione, menu, rilascio…) vengono sempre emessi, senza sottoscrizione.

## 3.5 Le scorciatoie da tastiera #

Una scorciatoia attiva un componente ovunque si trovi il focus nella finestra: l'utente non deve tornare sul pulsante per azionarlo. Ogni componente visivo le accetta, senza nulla da attivare.

    uo_enregistrer.of_register_shortcut("Ctrl+S")
    uo_actualiser.of_register_shortcut("F5")

### Scrivere una combinazione di tasti #

La combinazione è una stringa libera, normalizzata dalla libreria: maiuscole/minuscole, spazi e ordine dei modificatori non hanno alcuna importanza. `"Ctrl+Shift+S"`, `"ctrl + shift + s"` e `"SHIFT+CTRL+S"` indicano la stessa scorciatoia: è impossibile registrarne due varianti per sbaglio.

Elemento | Forme accettate
--- | ---
Modificatori | `Ctrl` (o `Control`), `Alt`, `Shift` — combinabili, in qualsiasi ordine
Tasto | una lettera `A`–`Z`, una cifra `0`–`9`, `F1` … `F24`, `Enter` (o `Return`), `Escape` (o `Esc`), `Delete` (o `Del`), `Insert`, `Home`, `End`, `PageUp`, `PageDown`

Questo elenco è esaustivo: un tasto assente (Tab, Barra spaziatrice, un tasto del tastierino numerico, un segno di punteggiatura) non attiva alcuna scorciatoia.

Un tasto singolo è una combinazione valida (`"F5"`). Una stringa vuota rimuove la scorciatoia dal componente.

> `"Enter"` ed `"Escape"` da soli non si registrano come scorciatoie: questi due tasti restano riservati al pulsante predefinito e al pulsante di annullamento (`ib_default` / `ib_cancel` del button). Combinati con un modificatore, tornano a essere combinazioni ordinarie (`"Ctrl+Enter"`).

### Chi vince in caso di conflitto #

Due componenti possono richiedere la stessa combinazione: succede spesso quando una finestra ospita più zone che hanno ciascuna il proprio « Salva ». L'arbitraggio segue questo ordine:

1. il componente che ha il focus da tastiera prevale su tutti gli altri: la scorciatoia di una zona attiva non viene mai oscurata da un vicino;
2. altrimenti vince il primo registrato.

Concorrono solo i componenti visibili e attivi della finestra in primo piano. Registrare di nuovo una combinazione su un componente che ne aveva già una la sostituisce senza cambiarne il rango: riconfigurare una finestra non rimescola le priorità.

### Scorciatoie di item #

L'overload a due argomenti collega la combinazione a un item del componente anziché al componente intero: il secondo argomento è l'identificatore dell'item:

    uo_barre.of_register_shortcut(/*combinazione*/ "Ctrl+N", /*item*/ "nouveau")
    uo_barre.of_register_shortcut(/*combinazione*/ "Ctrl+P", /*item*/ "imprimer")

### Rimuovere le scorciatoie #

    uo_barre.of_clear_shortcuts()      // componente E item

`of_reset()` e la distruzione del componente richiamano `of_clear_shortcuts()` al posto suo: un componente scomparso non trattiene mai una combinazione riservata.

### Il tasto Alt #

Alt da solo non viene catturato: dà il focus alla barra multifunzione, che mostra i propri keytip (vedere ribbon). La libreria non intercetta quindi le pressioni successive: è la barra multifunzione a leggerle, come se l'utente l'avesse cliccata. Esc o un secondo Alt restituiscono il focus al controllo abbandonato. Se nessuna barra multifunzione della finestra dichiara un keytip, Alt conserva il suo consueto comportamento Windows.

Membro | Effetto
--- | ---
`of_register_shortcut (string as_chord)` | Dichiara una scorciatoia per il componente; una stringa vuota la rimuove
`of_register_shortcut (string as_chord, string as_key)` | Dichiara una scorciatoia per un item, indicato dal suo identificatore
`of_clear_shortcuts ( )` | Rimuove tutte le scorciatoie del componente, item compresi

## 3.6 Riportare un componente a zero: `of_reset()` #

`of_reset()` riporta il componente al suo stato iniziale, come se fosse appena stato caricato:

- il contenuto viene svuotato (item, pagine, pannelli…);
- ogni proprietà torna al proprio valore predefinito (formattazione, colori, modalità, etichette);
- gli override di stile e i tooltip impostati sull'istanza vengono annullati;
- la cache delle proprietà sul lato PowerBuilder viene svuotata (le riletture ripartono dai valori predefiniti);
- anche lo stato nativo viene azzerato (menu contestuale, modalità di visualizzazione…).

    uo_grid.of_reset()          // ripartire da una griglia vuota
    // ... e poi ricostruire

> ⚠️ Riutilizzare un'istanza per visualizzare altro senza richiamare `of_reset()` conserva lo stato precedente (un colore, una modalità, un'altezza automatica). È la causa più frequente di un « residuo di visualizzazione » inspiegabile.

## 3.7 Diagnostica #

Membro | Effetto
--- | ---
`of_is_created ( )` → boolean | Il componente nativo esiste (runtime presente, host valido)
`of_is_ready ( )` → boolean | Il contenuto web è caricato (`ue_ready` già attivato)
`of_get_last_error ( )` → string | Ultimo messaggio di errore dettagliato della DLL, dopo un valore restituito `< 0`

Codici restituiti dai metodi `of_*`:

Valore restituito | Significato
--- | ---
`≥ 0` | OK (applicato o messo in coda)
`-2` | Componente non creato (runtime assente, host non valido)
`-4` | Operazione non riuscita (schermata, scrittura di file…)
`-5` | Argomento non valido (identificatore vuoto, valore fuori intervallo)
`-6` | Runtime WebView2 troppo vecchio per la funzione richiesta (stampa)

## 3.8 Esportare il rendering come immagine #

Ogni componente sa esportarsi come immagine, così come viene visualizzato:

    uo_pivot.of_save_as_png("C:\temp\tableau.png")
    uo_pivot.of_save_as_jpg("C:\temp\tableau.jpg")

Per stamparlo anziché esportarlo, veda Stampare.

Utile per un report, un allegato di posta elettronica o la traccia di un incidente. Il componente deve essere creato e il suo contenuto caricato.

## 3.9 Ciclo di vita #

1. Costruzione: la webview viene creata già alla costruzione dell'userobject — indispensabile per l'hosting (schede, pannelli ancorabili): una webview creata dopo il reparenting del proprio HWND non viene visualizzata.
2. Coda di attesa: i comandi vengono messi in coda finché `ue_ready` non è attivato.
3. Pronto: `ue_ready`; la coda viene riprodotta nell'ordine.
4. Ridimensionamento: automatico, il componente segue la dimensione dell'userobject.
5. Distruzione: alla chiusura della finestra; la webview viene rilasciata, senza alcun processo orfano.

Richiami `PBT_Warmup()` una volta all'avvio dell'applicazione affinché questo ciclo risulti impercettibile (Installazione).

## 3.10 Buone pratiche #

- Imposti il tema predefinito e la lingua nell'oggetto applicazione, prima dell'apertura della prima finestra: i componenti non presenteranno alcun lampeggio di stile.
- Racchiuda ogni costruzione voluminosa tra `of_set_redraw(false)` e `of_set_redraw(true)`.
- Richiami `of_reset()` prima di riutilizzare un'istanza per un altro contenuto.
- Non blocchi il thread dell'interfaccia con un lungo ciclo PowerScript tra la creazione e la visualizzazione: l'inizializzazione della webview ha bisogno del ciclo dei messaggi (vedere FAQ).

← Primi passi · Sommario · Temi →