Vega — Layout in der Praxis
Vega kennt keinen Layoutmanager mit Zwängen und Gewichten. Es gibt zwei Mittel, und beide sind einfach genug, um sie im Kopf zu behalten: Align verteilt Fläche, Anchors verteilt Zuwachs. Alles Weitere ergibt sich aus der Reihenfolge, in der Kinder angelegt werden.
→ Vega-Guides · Eigenschaften · Anwendungen aufbauen
Die Reihenfolge ist das Layout
ApplyLayout geht die Kinder der Reihe nach durch. Jedes ausgerichtete Kind schneidet sich seinen Streifen vom verbleibenden Rest ab; was übrig bleibt, bekommt das AL_CLIENT-Kind.
+--------------------------------+
| kopf AL_TOP |
+--------+-+---------------------+
| links |t| mitte |
| AL_LEFT|e| AL_CLIENT |
| |i| |
| |l| |
+--------+-+---------------------+
| fuss AL_BOTTOM |
+--------------------------------+
Daraus folgen drei Regeln:
- Ränder zuerst,
AL_CLIENTzuletzt. Wer den Editor als erstes Kind anlegt, gibt ihm die ganze Fläche — die Leisten danach bekommen nichts mehr. - Zwei
AL_CLIENT-Kinder sind einer zu viel. Das zweite bekommt, was das erste übrig lässt: nichts. - Ein Streifen braucht seine Dicke. Bei
AL_TOP/AL_BOTTOMzähltHeight, beiAL_LEFT/AL_RIGHTzähltWidth; die jeweils andere Angabe wird überschrieben.
ApplyLayout wirkt eine Ebene tief
ApplyLayout setzt Left/Top/Width/Height der eigenen Kinder direkt — nicht über SetBounds. Ein Container erfährt davon also nichts und richtet seine eigenen Kinder nicht aus. Wer verschachtelt, zieht das im OnResize des Fensters nach:
fn OnResize(sender: TControl): void {
if (g_mitte != null) { g_mitte.ApplyLayout(); }
g_form.Invalidate();
}
Und einmal von Hand nach ShowForm, damit schon das erste Bild stimmt.
Anker
Anchors entscheidet, was beim Vergrößern mitwandert. Es ist eine Bitmaske:
| Konstante | Wert | Wirkung |
|---|---|---|
ANCHOR_LEFT | 1 | Abstand zum linken Rand bleibt |
ANCHOR_TOP | 2 | Abstand nach oben bleibt |
ANCHOR_RIGHT | 4 | Abstand zum rechten Rand bleibt |
ANCHOR_BOTTOM | 8 | Abstand nach unten bleibt |
Vorgabe ist ANCHOR_LEFT | ANCHOR_TOP — das Element klebt oben links. Zwei gegenüberliegende Anker bedeuten mitwachsen: ANCHOR_LEFT | ANCHOR_RIGHT zieht die Breite mit dem Fenster.
Anker und Align schließen sich aus: Ein ausgerichtetes Kind bekommt seine Geometrie ohnehin vom Layout.
Splitter und ScrollBox
NewSplitter(AL_LEFT)legt einen Ziehbalken an, der die davor angelegte Spalte greifbar macht.MinSizeverhindert, dass sie ganz zugezogen wird. Der Splitter selbst ist ein ausgerichtetes Kind und gehört unmittelbar hinter das, was er greifen soll.NewScrollBox()mitAutoScroll := truezeigt Bildlaufleisten, sobald der Inhalt größer ist als die Fläche. Kinder darin behalten ihre Koordinaten; gescrollt wird der Ausschnitt.
Vollständiges Beispiel
Kopfzeile, Fußzeile mit rechts geankertem Knopf, linke Spalte mit Splitter, verschachtelter Container mit ScrollBox:
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.Layout;
import Vega.Backend;
import Vega.BackendAuto;
import Vega.Forms;
var g_app: TApplication;
var g_form: TForm;
var g_mitte: TPanel;
fn OnBeenden(sender: TControl): void { g_app.Terminate(); }
// ApplyLayout wirkt nur eine Ebene tief: die Kinder des Fensters werden
// ausgerichtet, deren eigene Kinder nicht. Verschachtelte Container ziehen
// ihr Layout deshalb hier nach.
fn OnResize(sender: TControl): void {
if (g_mitte != null) { g_mitte.ApplyLayout(); }
g_form.Invalidate();
}
fn main(): int64 {
g_app := new TApplication(NewPlatformBackend());
if (!g_app.Ready) { PrintLn("Kein Fenstersystem erreichbar."); return 1; }
g_form := new TForm(560, 360, "Layout");
g_form.OnResize := OnResize;
// 1. Kopfzeile
var kopf: TPanel := new TPanel();
kopf.Height := 32;
kopf.Align := AL_TOP;
kopf.SetParent(g_form);
// 2. Fusszeile mit einem Knopf, der rechts unten klebt
var fuss: TPanel := new TPanel();
fuss.Height := 40;
fuss.Align := AL_BOTTOM;
fuss.SetParent(g_form);
var ende: TButton := new TButton("Beenden");
ende.SetBounds(430, 6, 120, 28);
ende.Anchors := ANCHOR_RIGHT | ANCHOR_BOTTOM;
ende.OnClick := OnBeenden;
ende.SetParent(fuss);
// 3. Linke Spalte, danach der Splitter, der sie greifbar macht
var links: TPanel := new TPanel();
links.Width := 160;
links.Align := AL_LEFT;
links.SetParent(g_form);
var teiler: TSplitter := NewSplitter(AL_LEFT);
teiler.MinSize := 80;
teiler.SetParent(g_form);
// 4. Rest: ein Container, der seine eigenen Kinder ausrichtet
g_mitte := new TPanel();
g_mitte.Align := AL_CLIENT;
g_mitte.SetParent(g_form);
var oben: TLabel := new TLabel("obere Haelfte");
oben.Height := 24;
oben.Align := AL_TOP;
oben.SetParent(g_mitte);
var rest: TScrollBox := NewScrollBox();
rest.Align := AL_CLIENT;
rest.AutoScroll := true;
rest.SetParent(g_mitte);
// Inhalt, der breiter ist als die Flaeche — dafuer die ScrollBox
var breit: TLabel := new TLabel("ein sehr breiter Inhalt, der scrollen muss");
breit.SetBounds(8, 8, 900, 20);
breit.SetParent(rest);
if (!g_app.ShowForm(g_form)) { return 2; }
g_form.ApplyLayout();
OnResize(g_form);
g_app.Run();
g_app.Shutdown();
return 0;
}
Übersetzen: lyxc layout.lyx -I . -I platform/linux -o layout aus der Wurzel von lyx-vcl. Nachgemessen mit lyxc 1.1.3I, übersetzt fehlerfrei.
Wenn das Layout nicht stimmt
| Symptom | Ursache |
|---|---|
| Ein Streifen ist unsichtbar | Er wurde nach dem AL_CLIENT-Kind angelegt |
| Der Streifen hat die falsche Dicke | Bei AL_TOP/AL_BOTTOM zählt Height, nicht Width (und umgekehrt) |
| Kinder eines Containers liegen übereinander | Sein ApplyLayout wird nie gerufen |
| Beim ersten Bild sitzt alles falsch, nach dem ersten Ziehen richtig | ApplyLayout nach ShowForm fehlt |
| Ein Knopf wandert beim Vergrößern nicht mit | Anchors steht auf der Vorgabe (links/oben) |
Letzte Aktualisierung: 2026-08-19 — Beispiel mit lyxc 1.1.3I übersetzt; Splitter/ScrollBox gegen Vega/Layout.lyx abgeglichen.
