From the documentation of RAVAL, the MIT library of the books: the same as in its repository.
This page is available in Italian only for now.
Log e impostazioni — RAVAL 2.2
Le due cose che ogni programma vero si scrive il primo giorno: un log che dice cosa è successo, anche sul computer del cliente, e un file di impostazioni che ricorda le scelte dell'utente. In RAVAL sono scritte da zero, con licenza MIT come il resto della libreria; le idee vengono dal modo in cui lavorano i programmi dell'autore (livelli, file che ruota, riga di avvio, valori mancanti aggiunti al file).
Spiegazione con un esempio completo: TUTORIAL.md, capitolo 16. Ogni membro, con la sua firma, è nel riferimento API.md. Le prove sono in TEST_RAVAL\ProveApp.cs.
Il log — App\RLog.cs, UI\RLogView.cs
RLog.Start("Astrip", "1.4.0", "log/astrip.log"); // la prima riga: nome, versione, computer, .NET, pid
RLog.CatchUnhandled(); // anche le eccezioni che nessuno prende
RLog.Info("progetto aperto: " + percorso);
RLog.Error("salvataggio non riuscito", ex);
RLog.Stop(); // alla fine: scrive quello che resta
| Membro | Fa |
|---|---|
Error, Warning, Info, Debug, Trace | una riga del livello: «2026-11-06 15:04:05.123 INF [1] testo» (data, livello, thread, testo) |
Level | il livello meno importante scritto (Info: niente Debug e Trace); Enabled(livello) per non costruire testi costosi che non verrebbero scritti |
Console, Colors, TrueColor | le righe anche sulla console, colorate: l'ora attenuata, la sigla del livello nel suo colore (errori rossi, avvisi arancio, Info blu, Debug e Trace grigi), il testo nel colore del livello o nel suo; con TrueColor (da solo in Windows Terminal e con COLORTERM=truecolor) i colori esatti a 24 bit, se no i più vicini fra i 16 della console; mandata in un file, la console resta senza colori |
Info(testo, "#2b8a3e"), Debug(testo, colore), Add(livello, testo, colore) | una riga in un colore suo, da trovare a colpo d'occhio (una fase, un apparecchio, un risultato) |
MaxBytes, MaxFiles | il file ruota oltre 10 MB e ne restano 5: app.log, app.1.log ... app.4.log |
Recent(), RecentLines | le ultime 2000 righe in memoria, per una finestra del log aperta dopo |
Written | ogni riga scritta, sul thread del log |
Flush() | aspetta che sia scritto tutto quello che è stato registrato finora |
RLogView | il log dal vivo in una finestra, con gli stessi colori della console; filtro, «Pause», «Clear» |
Le impostazioni — App\RSettings.cs, RJsonSettings.cs, RIniSettings.cs
RSettings s = RSettings.Open(RSettings.Folder("Astrip") + "/settings.json"); // .ini per un file INI
int porta = s.GetInt("server.port", 5080);
s.Set("server.port", 5081); // il file si salva da solo mezzo secondo dopo
s.Remember(this, "window.main"); // la finestra riapre dov'era
var recenti = new RRecentFiles(s, "files.recent"); // File → Recenti
| Membro | Fa |
|---|---|
Open(file) | le impostazioni di un file, già lette: INI per «.ini», JSON per le altre estensioni |
Folder(app) | la cartella delle impostazioni: %APPDATA%\app su Windows, ~/.config/app su Linux e macOS |
GetString, GetInt, GetDouble, GetBool, GetList | un valore con il suo predefinito; un valore mancante o illeggibile dà il predefinito |
Set, SetList, Remove, Contains, Keys() | scrivere, togliere, cercare |
AddMissing | una chiave letta e non trovata si scrive con il suo predefinito (vero) |
AutoSave, SaveDelayMs, Save(), Dirty | il salvataggio ritardato, o subito |
Changed | dopo ogni Set che ha cambiato un valore, con la chiave |
Remember(finestra, nome) | posizione, misura e finestra ingrandita (RWindowMemory) |
RRecentFiles | gli ultimi file aperti, in cima il più recente, e il menu che li elenca |
Le chiavi sono percorsi con i punti. In JSON «server.port» è il campo port dell'oggetto server; in INI è la chiave port della sezione [server], e la sezione è tutto quello che sta prima dell'ultimo punto («window.main.x» è x in [window.main]). Le stesse chiamate valgono per i due formati.
Il JSON si scrive rientrato e con gli accenti come sono («città», non città): il file è fatto anche per essere aperto e corretto a mano.
Perché è fatto così
- Chi scrive nel log non aspetta il disco. La riga va in una coda e la scrive un thread del log: una chiamata costa uguale sul thread dell'interfaccia e su un thread di lavoro, e le righe di thread diversi non si mescolano mai a metà (la prova scrive 400 righe da quattro thread e le ritrova tutte intere).
- Il file del log ruota. Un programma che resta acceso per mesi non riempie il disco.
- Ogni lettura ha il suo predefinito. Un file mancante o rovinato non ferma mai il programma; un file che non si legge si rinomina «.bad» e si scrive un avviso nel log, così la copia dell'utente non si perde.
- Le chiavi lette vengono scritte nel file (
AddMissing): dopo il primo avvio il file elenca tutte le opzioni del programma, e chi lo modifica a mano le vede tutte. - Il salvataggio aspetta mezzo secondo. Una finestra trascinata manda centinaia di posizioni: il file si scrive una volta sola, alla fine. Si scrive un file temporaneo e poi lo si rinomina, così un arresto a metà lascia il file vecchio, non uno spezzato.
- Il file INI resta quello dell'utente. Commenti, righe vuote e ordine delle chiavi restano dove sono; un valore cambiato riscrive solo la sua riga. Il valore è tutto quello che segue il primo «=»: un «;» dentro un valore (un percorso, una lista) ne fa parte, e i commenti vanno su una riga a sé.
- La finestra ricorda la misura di quando era normale. Chiusa ingrandita, riapre ingrandita, e quando la si riduce torna al suo posto. Se lo schermo su cui stava non c'è più (un portatile senza il monitor), si apre al centro dello schermo principale invece che fuori dalla vista.
Il tema — App\RTheme.cs, UI\RThemes.cs
| Membro | Fa |
|---|---|
RThemes.Standard() | i colori dei controlli di RAVAL nei due temi (Back, Panel, Ink, InkSoft, Border, Bar, Tree, StatusBar, StatusInk, ChartBack, ChartGrid, ChartInk): la tavolozza grafite di ASTRIP; si aggiungono i propri con Color prima di Apply |
RTheme.Mode (RThemeMode: Light, Dark, System) · IsDark · Toggle() | la scelta, che cambia il tema di tutta l'applicazione mentre gira; se sullo schermo ora è scuro; chiaro ↔ scuro |
RTheme.Remember(impostazioni, chiave, predefinito) | legge «ui.theme», lo applica, lo riscrive a ogni cambio |
RTheme.Fill(menu) · RTheme.Button() · Changed | il menu con le tre scelte e la spunta; il bottone sole/luna; l'evento |
Le lingue — App\RLang.cs
| Membro | Fa |
|---|---|
RLang.Open(cartella, lingua) · Use(lingua) · Language · Languages() | i file delle lingue («it.json» o «it.ini»), la lingua in uso («» all'apertura: quella del sistema), quelle che hanno un file |
RLang.T(chiave, predefinito) · T(chiave, predefinito, valori...) | il testo nella lingua in uso; una chiave che manca si scrive nel file con il predefinito, da tradurre |
controllo.Tr(chiave, predefinito) · RLang.Bind(oggetto, proprietà, chiave, predefinito) | un testo legato che cambia con la lingua (Text, Header, Title, PlaceholderText o Content secondo il controllo); legami deboli |
Changed · Save() · Extension · BoundCount | dopo un cambio; il file scritto subito; «.json» o «.ini» per le lingue nuove |
| le chiavi «raval.*» | i testi di RAVAL (bottoni e titoli di RDialog, menu del tema), già in italiano |
Inciampi
- Un pennello tenuto in un campo non cambia con il tema (trovato in ASTRIP): un controllo disegnato a mano chiede i colori in
RenderconThemeBrushe si ridisegna conOnThemeChanged; preso all'avvio, il pennello resta quello del primo tema. Per fotografare nei due temi, fra il cambio e la foto si fa girare il dispatcher. - Le righe scritte prima che la vista entri nella finestra andavano perse.
RLogViewleggeva le righe in memoria quando veniva creata e ascoltavaWrittensolo dopo, quando entrava nella finestra: quello che il programma scriveva in mezzo non compariva da nessuna parte. Ora la vista prima si iscrive aWrittene poi leggeRecent. Una riga scritta proprio in quel momento sta in tutti e due; il numero progressivo della riga (RLogEntry.Number) fa saltare la seconda copia. - I numeri delle righe non arrivano in ordine. Il numero si assegna quando la riga nasce, ma due thread possono mettere in coda la 6 prima della 5. Per questo la vista riconosce le copie con l'insieme dei numeri già presi, e non con «numero minore dell'ultimo», che avrebbe scartato la 5.
- Le voci di un
ListBoxdi Fluent sono alte come un bottone (margine interno 12 × 9): un log ne mostra la metà.RLogViewle stringe con uno stile messo solo sulla sua lista:RStyles.Apply(controllo), che non tocca il resto dell'applicazione.