Label mit Zeilenabstand erweitern

Rund um die LCL und andere Komponenten
ArchChem
Beiträge: 22
Registriert: Mo 11. Jul 2022, 10:41

Label mit Zeilenabstand erweitern

Beitrag von ArchChem »

Hallo allerseits,

ich suche eine Möglichkeit, einen Label (entweder TLabel oder vorzugsweise auch TBCLabel) so zu erweitern, dass bei einem Zeilenumbruch der Zeilenabstand eingestellt werden kann.

Wie würde man das am Besten angehen? Leider werde ich aus dem Wiki bzw. den Units nicht wirklich schlau.

Vielen Dank schon mal!

Benutzeravatar
Winni
Beiträge: 1423
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Label mit Zeilenabstand erweitern

Beitrag von Winni »

Hi!


Das TBCLabel besitzt die Property FontEx.

Diese besitzt wiederum PaddingBottom und PaddingTop.

Damit kannst Du den Abstand oben und unten einstellen.

Winni

ArchChem
Beiträge: 22
Registriert: Mo 11. Jul 2022, 10:41

Re: Label mit Zeilenabstand erweitern

Beitrag von ArchChem »

Hallo,

danke für die schnelle Antwort! Die Eigenschaft FontEx.PaddingBottom verändert den Abstand unter dem (gesamten) Text, nicht aber zwischen den Zeilen. Oder habe ich da etwas übersehen?

Benutzeravatar
theo
Beiträge: 9580
Registriert: Mo 11. Sep 2006, 19:01

Re: Label mit Zeilenabstand erweitern

Beitrag von theo »

Kannst du mal ein bisschen erklären, worum es dir geht?
Ein TLabel ist ja nicht direkt ein mehrzeiliges Textfeld.
Da wäre TStaticText schon geeigneter, aber auch dort kann man (afaics) den Zeilenabstand nicht verändern.
Wahrscheinlich kommst du um das selber TextOuten nicht herum.
Aber sag doch mal wozu.

ArchChem
Beiträge: 22
Registriert: Mo 11. Jul 2022, 10:41

Re: Label mit Zeilenabstand erweitern

Beitrag von ArchChem »

Ich möchte gerne einen mehrzeiligen Text (mit automatischen sowie manuellen Zeilenumbrüchen) darstellen und dabei einen Abstand zwischen den Zeilen einstellen können.

Benutzeravatar
theo
Beiträge: 9580
Registriert: Mo 11. Sep 2006, 19:01

Re: Label mit Zeilenabstand erweitern

Beitrag von theo »

Das klingt leider einfacher als es ist.
Mit den Komponenten die letztlich Canvas.TextRect benutzen hast du keinen Einfluss auf Zeilenhöhe/-abstand.

Wie gesagt, das musst du wahrscheinlich selber mit TextOut ausgeben und umbrechen!
Oder du versuchst es mit einer potenteren Komponente, wie z.B. LazRichView (habe ich nicht getestet).

Ich habe kürzlich etwas in dieser Richtung gemacht, bin aber noch nicht an meinem Ziel.
Für deinen Zweck würde es vielleicht reichen.
Fall es dich interessiert, kann ich morgen mal schauen, ob das geeignet wäre.

ArchChem
Beiträge: 22
Registriert: Mo 11. Jul 2022, 10:41

Re: Label mit Zeilenabstand erweitern

Beitrag von ArchChem »

Das wäre nett, vielen Dank dir!

Benutzeravatar
Winni
Beiträge: 1423
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Label mit Zeilenabstand erweitern

Beitrag von Winni »

Hi!

Workaround 1: Nimm ein TPanel und schreib Deinen Text auf den Canvas - mit dem gewünschten Zeilenabstand

Workaround 2: Nimm eine Listbox und regel den Zeilenabstand über die Itemheight


Die Einstellung des Zeilenabstands wurde leider bei Delphi / Lazarus vergessen. Wurde halt von Menschen gemacht, die wenig Ahnung von Typographie und Graphik hatten.

Winni

ArchChem
Beiträge: 22
Registriert: Mo 11. Jul 2022, 10:41

Re: Label mit Zeilenabstand erweitern

Beitrag von ArchChem »

Hallo Winni,
Winni hat geschrieben:
Do 17. Nov 2022, 22:27
Workaround 1: Nimm ein TPanel und schreib Deinen Text auf den Canvas - mit dem gewünschten Zeilenabstand
Wie würde das praktisch aussehen? Ich müsste dann jeden Zeilenumbruch des Fließtexts selbst berechnen und an passender Stelle einfügen?
Winni hat geschrieben:
Do 17. Nov 2022, 22:27
Workaround 2: Nimm eine Listbox und regel den Zeilenabstand über die Itemheight
Auch hier würde dann der automatische Umbruch fehlen.

Ich habe einen längeren Fließtext, welcher umgebrochen werden soll.
Winni hat geschrieben:
Do 17. Nov 2022, 22:27
Die Einstellung des Zeilenabstands wurde leider bei Delphi / Lazarus vergessen. Wurde halt von Menschen gemacht, die wenig Ahnung von Typographie und Graphik hatten.
Da wird es Zeit, das mal zu ergänzen :D

Benutzeravatar
theo
Beiträge: 9580
Registriert: Mo 11. Sep 2006, 19:01

Re: Label mit Zeilenabstand erweitern

Beitrag von theo »

@ArchChem: Ich habe mir meinen Code wie versprochen noch einmal angeschaut und er eignet sich momentan leider nicht für deinen Zweck.
Sorry, wenn ich dir falsche Hoffnungen gemacht habe.
ArchChem hat geschrieben:
Fr 18. Nov 2022, 09:58
Wie würde das praktisch aussehen? Ich müsste dann jeden Zeilenumbruch des Fließtexts selbst berechnen und an passender Stelle einfügen?
Dein Code würde den Punkt anhand der effektiven, Font-spezifischen Textweite errechnen (Canvas.TextExtent)
ArchChem hat geschrieben:
Fr 18. Nov 2022, 09:58
Auch hier würde dann der automatische Umbruch fehlen.
Richtig.
ArchChem hat geschrieben:
Fr 18. Nov 2022, 09:58
Winni hat geschrieben:
Do 17. Nov 2022, 22:27
Die Einstellung des Zeilenabstands wurde leider bei Delphi / Lazarus vergessen. Wurde halt von Menschen gemacht, die wenig Ahnung von Typographie und Graphik hatten.
Da wird es Zeit, das mal zu ergänzen :D
Nur zu! Lazarus wird von Menschen wie dir entwickelt. :D

Wenn man etwas konkreter wüsste, was dein Anwengungsfall ist (Unter "ich möchte gerne..." kann ich mir meistens nicht viel vorstellen), könnte man dir vielleicht auch Alternativen vorschlagen.

ArchChem
Beiträge: 22
Registriert: Mo 11. Jul 2022, 10:41

Re: Label mit Zeilenabstand erweitern

Beitrag von ArchChem »

theo hat geschrieben:
Fr 18. Nov 2022, 10:19
Nur zu! Lazarus wird von Menschen wie dir entwickelt. :D
Gerne, wenn es sich ergibt!

Ich möchte die Liedpräsentationssotware Cantara ein bisschen ausbauen, indem dort Zeilenabstände eingefügt werden können (Bilder siehe hier). Bisher können die Schriftgröße, -farbe und -art eingestellt werden, aber eben nicht der Zeilenabstand.

Technisch habe ich das ganze mit TLabel(s) gelöst, welche bei Laufzeit an passender Stelle positioniert werden. Mir ist bewusst, dass das keine optimale Lösung ist (da TLabel-Komponenten ja eigentlich nicht für längere Texte gedacht sind), aber eine ressourcensparende und (bisher) auch gut funktionierende. Nichtsdestotrotz bin ich gerne offen für andere Ideen. Einen HTMLViewer habe ich schon probiert, das finde ich allerdings für meine Zwecke zu viel des Guten (und ist auch sehr buggy).
theo hat geschrieben:
Fr 18. Nov 2022, 10:19
@ArchChem: Ich habe mir meinen Code wie versprochen noch einmal angeschaut und er eignet sich momentan leider nicht für deinen Zweck.
Sorry, wenn ich dir falsche Hoffnungen gemacht habe.
Vielen Dank fürs Nachschauen!

wp_xyz
Beiträge: 4427
Registriert: Fr 8. Apr 2011, 09:01

Re: Label mit Zeilenabstand erweitern

Beitrag von wp_xyz »

ArchChem hat geschrieben:
Fr 18. Nov 2022, 09:58
Wie würde das praktisch aussehen? Ich müsste dann jeden Zeilenumbruch des Fließtexts selbst berechnen und an passender Stelle einfügen?
Es gibt die Funktion DrawText, die, wenn man in dem Flags-Parameter das Bit DT_WORDBREAK gesetzt hat, den Text automatisch umbricht - die wird von der Ausgaberoutine von TLabel verwendet. Allerdings bleibt der Text unverändert, sie schreibt keine Zeilenumbrüche in den Text hinein, und ich kenne auch keine Funktion, die sowas pixelgenau macht (allerdings: TMemo kann das...).

Wenn du auf den pixelgenauen Umbruch verzichten kannst, gibt es allerdings auch die Funktion WrapText, die Zeilenumbrüche nach einer bestimmten Zeichenanzahl einfügt. Bei den heute verwendeten Proportionalfonts kann das aber relativ ungenau sein. Man müsste die Breite des verfügbaren Rechtecks durch die mittlere Breite eines Zeichens dividieren (oder um auf der sicheren Seite zu sein: durch die Breite eine breiten Zeichens, z.B., des 'M'), und würde dann mit diesem Wert in die Funktion WrapText gehen.

Den so mit Linebreaks versehenen Strings steckt man als Text in eine StringList und erhält dann die einzelnen Zeilen, die man mit Standardroutinen ausgibt. Und beim Weiterschalten auf die nächste Zeile fügt man den zusätzlichen Zeilenabstand ein.

Etwa so, wie in einer Paintbox einfach zu testen - hier wird der Zeilenabstand um 50% vergrößert (Zeile mit "inc(y, ...)"):

Code: Alles auswählen

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
  R: TRect;
  s: String;
  y: Integer;
  i, n, h: Integer;
  L: TStrings;
begin
  s := 'This is a long, long, long, long, long, long text.';

  R := Rect(0, 0, Paintbox1.Width, Paintbox1.Height);
  Paintbox1.Canvas.Brush.Color := clWhite;
  Paintbox1.Canvas.FillRect(R);
  InflateRect(R, -8, -8);
  n := R.Width div Paintbox1.Canvas.TextWidth('0');

  L := TStringList.Create;
  L.Text := WrapText(s,  n);
  y := R.Top;
  h := Paintbox1.Canvas.TextHeight('Tg');
  for i := 0 to L.Count-1 do
  begin
    Paintbox1.Canvas.TextOut(R.Left, y, L[i]);
    inc(y, h*3 div 2);
  end;
  L.Free;
end;
Oder - ohne den Umweg über die StringList - du gehst wirklich den String Zeichen für Zeichen durch, extrahierst die Wörter, schreibst die auf den Canvas, und wenn ein Wort über den rechten Rand hinausreicht, beginnst du eine neue Zeile, deren Abstand du frei wählen kannst.

Aber ehrlich: Ist es das wert? Was stört dich an dem "normalen" Zeilenabstand?

Benutzeravatar
theo
Beiträge: 9580
Registriert: Mo 11. Sep 2006, 19:01

Re: Label mit Zeilenabstand erweitern

Beitrag von theo »

@wp: DrawText ist aber im API Interface.
Das LCL-Level Pendant in "Graphics" ist "TextRect", wie oben schon erwähnt.

Code: Alles auswählen

 procedure TextRect(ARect: TRect; X, Y: integer; const Text: string;  const Style: TTextStyle); virtual;     
Wobei

Code: Alles auswählen

TTextStyle = packed record
...
    Wordbreak : boolean;  
...
Zeilenabstände kann das aber nicht variieren.

Das mit deinem WrapText Beispiel kann eine einfache Lösung sein, insb. mit Monospace Fonts. (Courier etc..).
Mit proportionalen Fonts ist es ungenau, aber wenn's nicht stört, kann man sich damit Arbeit sparen.

Ich hatte auch daran gedacht, wollte aber zuerst wissen wie ArchChem das einsetzen will.

ArchChem
Beiträge: 22
Registriert: Mo 11. Jul 2022, 10:41

Re: Label mit Zeilenabstand erweitern

Beitrag von ArchChem »

@theo & @wp_xyz, ich danke euch für eure Hinweise!
wp_xyz hat geschrieben:
Fr 18. Nov 2022, 10:51
Es gibt die Funktion DrawText, die, wenn man in dem Flags-Parameter das Bit DT_WORDBREAK gesetzt hat, den Text automatisch umbricht - die wird von der Ausgaberoutine von TLabel verwendet. Allerdings bleibt der Text unverändert, sie schreibt keine Zeilenumbrüche in den Text hinein, und ich kenne auch keine Funktion, die sowas pixelgenau macht (allerdings: TMemo kann das...).
Super, danke! Nun hatte ich die Idee, einfach die DrawText-Funktion zu überladen und dort den Zeilenabstand einzufügen. Leider kann ich diese nicht wirklich lokalisieren. In der Unit winapi.inc befindet sich eine, die ruft jedoch nur die Funktion WidgetSet.DrawText auf. Weißt du vielleicht, wo sich die Originalfunktion befindet?
wp_xyz hat geschrieben:
Fr 18. Nov 2022, 10:51
Wenn du auf den pixelgenauen Umbruch verzichten kannst, gibt es allerdings auch die Funktion WrapText, die Zeilenumbrüche nach einer bestimmten Zeichenanzahl einfügt. Bei den heute verwendeten Proportionalfonts kann das aber relativ ungenau sein. Man müsste die Breite des verfügbaren Rechtecks durch die mittlere Breite eines Zeichens dividieren (oder um auf der sicheren Seite zu sein: durch die Breite eine breiten Zeichens, z.B., des 'M'), und würde dann mit diesem Wert in die Funktion WrapText gehen.
Das klingt gut, kommt aber für meinen Anwendungsfall nicht in Frage. Ich möchte gerade ein typographisch möglichst schönes Ergebnis erzielen, und dazu brauche ich einen präzisen Umbruch an der richtigen Stelle.
wp_xyz hat geschrieben:
Fr 18. Nov 2022, 10:51
Oder - ohne den Umweg über die StringList - du gehst wirklich den String Zeichen für Zeichen durch, extrahierst die Wörter, schreibst die auf den Canvas, und wenn ein Wort über den rechten Rand hinausreicht, beginnst du eine neue Zeile, deren Abstand du frei wählen kannst.
Wie kann ich denn herausfinden, ob ich über den Rand gekommen bin (außer visuell)?
theo hat geschrieben:
Fr 18. Nov 2022, 11:18
Das LCL-Level Pendant in "Graphics" ist "TextRect", wie oben schon erwähnt.
Danke! Auch dieses greift auf die Function DrawText zurück, welche ich nun irgendwie lokalisieren und verstehen müsste... In den inc-Dateien scheint keine Implementierung zu stehen.

Socke
Lazarusforum e. V.
Beiträge: 3082
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Label mit Zeilenabstand erweitern

Beitrag von Socke »

ArchChem hat geschrieben:
Fr 18. Nov 2022, 16:39
@theo & @wp_xyz, ich danke euch für eure Hinweise!
wp_xyz hat geschrieben:
Fr 18. Nov 2022, 10:51
Es gibt die Funktion DrawText, die, wenn man in dem Flags-Parameter das Bit DT_WORDBREAK gesetzt hat, den Text automatisch umbricht - die wird von der Ausgaberoutine von TLabel verwendet. Allerdings bleibt der Text unverändert, sie schreibt keine Zeilenumbrüche in den Text hinein, und ich kenne auch keine Funktion, die sowas pixelgenau macht (allerdings: TMemo kann das...).
Super, danke! Nun hatte ich die Idee, einfach die DrawText-Funktion zu überladen und dort den Zeilenabstand einzufügen. Leider kann ich diese nicht wirklich lokalisieren. In der Unit winapi.inc befindet sich eine, die ruft jedoch nur die Funktion WidgetSet.DrawText auf. Weißt du vielleicht, wo sich die Originalfunktion befindet?
Viel mehr gibt es da leider nicht. Die Implementierung von WidgetSet.DrawText findest du für Windows in der Unit Win32Int, genauer in der Datei lazarus\lcl\interfaces\win32\win32winapi.inc in der Methode TWin32WidgetSet.DrawText. Spoiler: bis auf ein wenig Berechnung der Textbreite wird das eigenliche Zeichnen auch nur an Windows weitergeleitet.
Du kannst also deine Methode direkt dort implementieren, wo du sie brauchst (oder als Helper zu einem Canvas?).
ArchChem hat geschrieben:
Fr 18. Nov 2022, 16:39
wp_xyz hat geschrieben:
Fr 18. Nov 2022, 10:51
Oder - ohne den Umweg über die StringList - du gehst wirklich den String Zeichen für Zeichen durch, extrahierst die Wörter, schreibst die auf den Canvas, und wenn ein Wort über den rechten Rand hinausreicht, beginnst du eine neue Zeile, deren Abstand du frei wählen kannst.
Wie kann ich denn herausfinden, ob ich über den Rand gekommen bin (außer visuell)?
Mit Canvas.TextExtend kannst du die Größe ermitteln. Ausgehend von deiner Zielposition kannst du dann ausrechnen, ob dein Text zu groß ist.
Zuletzt geändert von Socke am Fr 18. Nov 2022, 17:06, insgesamt 1-mal geändert.
Grund: Quotes fehlerhaft
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten