Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Prüfen, ob Label zu klein bzw. zu viel Text


Happy_Penguin - Fr 11.03.16 15:57
Titel: Prüfen, ob Label zu klein bzw. zu viel Text
Hallo,

ich habe ein Programm, welches mehrzeilige Strings ähnlich wie eine PowerPoint-Präsentation anzeigen soll. Dabei besteht die entsprechende Form aus einem Label, der den gesamten Platz ausfüllt und den Text entsprechend umbricht (Align := alClient; WordWrap := True;). Nun möchte ich, dass, wenn der String zu lange ist und über das Fenster hinausgeht, die Schriftgröße des Labels so lange verkleinert wird, bis es passt.

Hat da jemand eine Idee? Signalisiert der Label, wenn der Platz nicht ausreicht?

Vielen Dank schon Mal für alle Antworten.


jaenicke - Fr 11.03.16 18:06

Hier findest du eine Demo wie so etwas vom Prinzip her aussieht:
http://www.delphi-forum.de/viewtopic.php?p=557541
Mit einem Label funktioniert das analog, aber eventuell ist selbst zeichnen ohnehin für dich besser.


Happy_Penguin - Sa 12.03.16 22:42

Hallo,

erst Mal Danke für die Antwort! Ich möchte aber an einem Label festhalten, da dort viele für mich nützliche Funktionen schon implementiert sind, wie automatischer Zeilenumbruch bzw. umfassende Ausrichtungsmöglichkeiten von Text. In einer PaintBox bzw. beim direkten Nutzen von Canvas müsste ich das doch größtenteils von Hand implementieren, oder?

Also ich brauche eigentlich nur eine Möglichkeit, dass der Label signalisiert, wenn sein Platz nicht mehr ausreicht.

Schönes Wochenende noch!


ub60 - So 13.03.16 13:31

Das sollte Dir weiterhelfen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TForm1.Button1Click(Sender: TObject);
var s : String;
    MaxBreite, Breite, Schriftgroesse : Integer;
begin
  MaxBreite:=Label1.Width;
  Schriftgroesse:=32;
  Label1.Font.Name:='Arial';
  Label1.Canvas.Font.Name:='Arial';
  s:='Das ist ein sehr, sehr langer Text für das Label';
  Label1.Caption:=s;
  repeat
    Label1.Font.Size:=Schriftgroesse;
    Label1.Canvas.Font.Size:=Schriftgroesse;
    Breite:=Label1.Canvas.TextWidth(s);
    Application.ProcessMessages;
    Dec(Schriftgroesse);
    Sleep(100);
  until Breite<MaxBreite;
end;


Eventuell geht es auch einfacher, aber der Quelltext funktioniert bei mit zufriedenstellend.
Für das Wordwrapping musst Du Dir überlegen, wie groß Dein Text minimal sein soll. Dann muss der String (sich wortweise vergrößernd) untersucht werden.
Für die zeilenweise Anpassung benötigst Du dann noch TextHeight.

edit:
Und jetzt das Ganze noch einmal für ein komplettes Wordwrapping. Dazu missbrauche ich allerdings ein (unsichtbares zweites Label:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
var s : String;
    MaxHoehe, Hoehe, Schriftgroesse : Integer;
begin
  MaxHoehe:=Label1.Height;
  Schriftgroesse:=32;
  Label1.Font.Name:='Arial';
  Label2.Font.Name:='Arial';
  s:='Das ist ein sehr, sehr langer Text für das Label. Und der Text soll jetzt für das Label passend gemacht werden.';
  Label1.Caption:=s;
  // Das ist ein Dummy-Label, was man unsichtbar machen kann.
  Label2.Caption:=s;
  Label2.WordWrap:=True;
  Label2.Width:=Label1.Width;
  Label2.AutoSize:=True;
  //ShowMessage(IntToStr(Label2.Width));
  repeat
    Label2.Width:=Label1.Width;  // Die Zeile ist wichtig!
    Label2.Font.Size:=Schriftgroesse;
    Application.ProcessMessages;
    Dec(Schriftgroesse);
    Sleep(100);
    Hoehe:=Label2.Height;
  until Hoehe<MaxHoehe;
  Label1.Font.Size:=Schriftgroesse+1;
end;


ub60


WasWeißDennIch - So 13.03.16 15:31

Ich würde es so versuchen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
function TextFitsInRect(DestRect: TRect; const Text: string;
  DestCanvas: TCanvas): Boolean;
var
  tmpCanvas: TCanvas;
  R: TRect;
begin
  tmpCanvas := TCanvas.Create;
  try
    tmpCanvas.Handle := DestCanvas.Handle;
    tmpCanvas.Font.Assign(DestCanvas.Font);
    R := DestRect;
    DrawText(tmpCanvas.Handle, PChar(Text), -1, R, DT_TOP or DT_LEFT or
      DT_WORDBREAK or DT_CALCRECT);
    Result := R.Height <= DestRect.Height;
  finally
    tmpCanvas.Free;
  end;
end;

procedure TFormTest.ButtonTestClick(Sender: TObject);
begin
  while not TextFitsInRect(LabelTest.ClientRect, LabelTest.Caption, LabelTest.Canvas) do
    LabelTest.Font.Size := LabelTest.Font.Size - 1;
end;


Happy_Penguin - Mo 14.03.16 20:37

Hallo,

danke für eure Antworten. Leider funktioniert es noch nicht :-(
ub60: Leider werden bei der Variante automatische Zeilenumbrüche nicht berücksichtigt. Gibt es da noch eine Möglichkeit, dies zu ändern?
WasWeißDennIch: Leider ist DrawText nur was für Windows-Nutzer. Deswegen kommt das für mich nicht in Frage.

Tut mir leid, dass ich euch mit dieser vielleicht nervigen Frage aufhalte. Aber ich habe auch nach langer Internetrecherche noch keine Lösung gefunden, die funktioniert. Im Prinzip soll der Label ja einfach nur bescheid sagen, wenn sein Platz nicht ausreicht.


WasWeißDennIch - Mo 14.03.16 20:45

Geht es um Firemonkey? Dann ist der Thread in der VCL-Sparte wohl nicht ganz richtig. Sei' s drum: evtl. geht es mit einem TTextLayout und dessen TextHeight-Eigenschaft, aber das habe ich jetzt nicht ausprobiert.


Martok - Mo 14.03.16 20:48

Lazarus (bzw. die LCL) hat für Label eine Eigeneschaft "OptimalFill". Dort nimmt man eine einfache binäre Suche und TextExtent um eine passende Größe zu finden. Vielleicht kannst du ja da was klauen [https://github.com/graemeg/lazarus/blob/upstream/lcl/include/customlabel.inc#L307] ;)


ub60 - Di 15.03.16 19:28

Ich kann das Problem nicht nachvollziehen. Bei mir funktioniert es (siehe Bilder).
Oder habe ich es falsch verstanden?

Label1

Label2

ub60