Eine Oberfläche muss nicht im Quelltext stehen. Das LFM-Format beschreibt sie als Datei; das Programm daneben enthält nur noch die Handler und drei Zeilen zum Laden. Damit lässt sich das Fenster ändern, ohne den Quelltext anzufassen — und ohne neu zu übersetzen.
Die Formatreferenz steht in LFM-Formularformat; dieser Guide zeigt den Arbeitsablauf.
→ Vega-Guides · Komponenten · LFM-Referenz
lfm 1
object Form1: TForm
Width = 360
Height = 220
Caption = 'Aus einer Datei geladen'
object Kopf: TPanel
Left = 0
Top = 0
Width = 360
Height = 40
Align = alTop
object Titel: TLabel
Left = 12
Top = 12
Width = 320
Height = 18
Caption = 'Dieser Aufbau steht in guide.lfm'
end
end
object Feld: TEdit
Left = 16
Top = 60
Width = 220
Height = 26
Text = 'Text aendern'
OnChange = FeldGeaendert
end
object Stand: TLabel
Left = 16
Top = 100
Width = 320
Height = 18
Caption = 'bereit'
end
object BtnEnde: TButton
Left = 220
Top = 150
Width = 120
Height = 28
Caption = 'Beenden'
OnClick = EndeKlick
end
end
object Name: TKlasse … end — verschachtelt wie der Steuerelementbaum.Name = Wert; Zeichenketten in einfachen Anführungszeichen.Align = alTop benutzt die Delphi-Schreibweise der Ausrichtung.OnClick = EndeKlick. Mit Anführungszeichen meldet der Lader rechts von einem Ereignis steht ein Name ohne Anfuehrungszeichen — nachgemessen mit lyxc 1.1.3I.
unit Main;
import std.io;
import Vega.Types;
import Vega.Events;
import Vega.Canvas;
import Vega.Theme;
import Vega.Control;
import Vega.Font;
import Vega.Strings;
import Vega.Lists;
import Vega.Style;
import Vega.StdCtrls;
import Vega.Edits;
import Vega.Layout;
import Vega.Backend;
import Vega.BackendAuto;
import Vega.Forms;
import Vega.LfmValue;
import Vega.LfmParse;
import Vega.LfmClasses;
import Vega.LfmLoad;
var g_app: TApplication;
var g_form: TForm;
var g_stand: TLabel;
fn FeldGeaendert(sender: TControl): void {
var e: TEdit := sender as TEdit;
var t: pchar := e.GetText();
g_stand.SetCaption(t);
}
fn EndeKlick(sender: TControl): void {
g_app.Terminate();
}
fn main(): int64 {
g_app := new TApplication(NewPlatformBackend());
if (!g_app.Ready) { PrintLn("Kein Fenstersystem erreichbar."); return 1; }
// Ohne Eintragung ist ein Handlername in der Datei nur eine Zeichenkette.
RegisterNotify("FeldGeaendert", FeldGeaendert);
RegisterNotify("EndeKlick", EndeKlick);
var ld: TLfmLoader := new TLfmLoader();
var res: TLfmResult := ld.LoadFile("guide.lfm", null);
if (!res.Ok()) {
PrintLn("Formular mit Fehlern:");
var i: int64 := 0;
while (i < res.ErrorCount()) {
var e: pchar := res.ErrorAt(i);
PrintLn(e);
i := i + 1;
}
}
if (res.Root == null) { PrintLn("Kein Formular geladen."); return 1; }
g_form := res.Root as TForm;
// Controls ueber ihren Namen aus der Datei holen
var sc: TControl := g_form.FindTyped("Stand", "TLabel");
if (sc != null) { g_stand := sc as TLabel; }
if (!g_app.ShowForm(g_form)) { return 2; }
g_app.Run();
g_app.Shutdown();
return 0;
}
Übersetzen: lyxc lfm.lyx -I . -I platform/linux -o lfm. Nachgemessen mit lyxc 1.1.3I, übersetzt fehlerfrei; die Datei wird zur Laufzeit relativ zum Arbeitsverzeichnis gelesen.
RegisterNotify(„EndeKlick“, EndeKlick) verbindet den Namen aus der Datei mit der Funktion. Ohne Eintragung ist der Name nur Text — der Lader meldet das mit Zeilennummer, statt den Knopf später stumm zu lassen. Für die anderen Ereignisarten: RegisterMouse, RegisterKey, RegisterChar, RegisterWheel, RegisterPaint.ld.LoadFile(pfad, null) liefert ein TLfmResult.res.Ok(), res.ErrorCount(), res.ErrorAt(i). Vorgabe ist nachsichtig: Das Fenster geht trotz Fehlern auf, damit man sieht, wo man steht. ld.Strict := true bricht stattdessen ab.g_form.FindTyped(„Stand“, „TLabel“) sucht über den Namen aus der Datei und prüft dabei die Klasse; null heißt „nicht gefunden„.
LfmSave(wurzel, pfad) schreibt einen bestehenden Steuerelementbaum als LFM-Datei — der Weg, um eine im Code aufgebaute Oberfläche in eine Datei zu überführen und ab da dort zu pflegen.
Dagegen: Für ein Fenster mit drei Knöpfen ist der Code kürzer als Datei plus Ladecode.
Im Regelzyklus einer sicherheitskritischen Anwendung hat das Laden eines Formulars nichts zu suchen. Ein LoadFile liest zur Laufzeit eine Datei, legt dabei Speicher an, baut einen Objektbaum auf und ruft am Ende Handler über Zeiger, deren Ziel erst die Datei bestimmt. Jeder dieser vier Punkte widerspricht dem, was @flight_crit zusagt: eine Laufzeit, die sich vorab nachweisen lässt.
Der Compiler weist die offensichtlichen Fälle ab (gemessen mit lyxc 1.1.3I):
@flight_crit
fn MitHeap(): int64 { var p: int64 := alloc(64); free(p, 64); return 0; }
sema error (line 8): Speicheranforderung unter @flight_crit nicht erlaubt 'alloc'
sema error: new ist unter @flight_crit nicht erlaubt — der Speicher muss ausserhalb angelegt und hereingereicht werden
sema error: lokales Feld unter @flight_crit nicht erlaubt (es entsteht per mmap, nicht auf dem Stapel)
Die Prüfung reicht nur bis zum eigenen Rumpf (#1701). Ruft eine@flight_crit-Funktion einen Helfer, der seinerseits alloziert, meldet der Compiler nichts — die Allokation ist dieselbe, sie wird nur nicht mehr gesehen. Ebenso geht ein Aufruf über einen Funktionszeiger durch, obwohl sein Ziel zur Übersetzungszeit nicht feststeht.
EinLfmLoader.LoadFilein einer@flight_crit-Funktion würde also nicht abgewiesen werden — er wäre trotzdem falsch.
Die brauchbare Aufteilung ist dieselbe wie bei jeder anderen Ressource:
| Phase | Was dort erlaubt ist |
|---|---|
| Initialisierung | Formular laden, Speicher anlegen, Handler eintragen, Fenster öffnen — hier gibt es kein WCET-Budget |
Regelzyklus (@flight_crit) | Nur rechnen und auf vorhandene Puffer schreiben; kein new, kein alloc, kein Dateizugriff, keine indirekten Aufrufe |
| Herunterfahren | Freigeben, speichern |
Wer eine Oberfläche über einer sicherheitskritischen Regelung baut, trennt beide sauber: Die Regelung läuft in ihrem eigenen Rahmen mit vorab angelegten Puffern, die Anzeige liest daraus und wird von der Ereignisschleife bedient. Vega selbst ist nicht für DAL-A/B-Code gedacht — es alloziert, zeichnet in Puffer und ruft Handler indirekt; das ist für eine Oberfläche genau richtig und für den Regelzyklus genau falsch.
→ DO-178C-Guide · Attribute & Pragmas
res bleibt das Element stumm.FindTyped liefert null — Name oder Klasse stimmen nicht; beide stehen in der Datei.
Letzte Aktualisierung: 2026-08-19 — Abschnitt „LFM und @flight_crit“ ergänzt (Reichweite der Prüfung mit lyxc 1.1.3I nachgemessen, #1701); Ablauf gegen Vega/LfmLoad.lyx und Vega/LfmClasses.lyx erhoben; Datei und Programm mit lyxc 1.1.3I übersetzt und das Laden nachgemessen.