![]() |
WordBreak innerhalb eines Wortes
Moin Moin ...
Man kann ja mit DrawText einen Text z.B. auf dem Canvas eines Bitmaps ausgeben. Wenn man eine fixe Rect-Größe hat und DT_WORDBREAK benutzt, dann wird der Text auch entsprechend an Hand der Leerzeichen bzw. CR/LF umgebrochen. Durch den Parameter DT_CALCRECT bekomme ich ja u.a. die Rect-Höhe zurück und falls ein besonders langes Wort über die maximal vorgegebene Rect-Breite hinaus gehen würde, wird auch diese entsprechend vergrößert. Und genau um diese langen Worte geht es mir. Beispielsweise ein Link, der ja keine Leerzeichen enthält und auch recht lang werden kann. Meiner Recherche zufolge, könnte ich zwar mit TRichEdit und einer festen Breite incl. dem richtigen Zeichensatz, die Komponente den Umbruch erledigen lassen und danach mit Lines[] die Zeilen abfragen. Nur wegen dieser Funktion möchte ich aber ungern die gesammte Komponente meinem Projekt hinzufügen. Da würde ich lieber eine eigene Funktion schreiben, wahrscheinlich eine Kombination aus WordWrap und GetTextExtentExPoint, welche mir das zu lange Wort entsprehend umbricht. Erste Ansätze wurden schon mal ![]() Danke schon mal für Eure Hilfe. |
AW: WordBreak innerhalb eines Wortes
Im Unicode gibt es irgendwo z.B. ein sogenanntes ZeroWidthSpace-Char, das ist eine Art Leerzeichen, mit der Breite 0, also man sieht es im Normalfall nicht, aber der Zeilenubruch kann sich an dieser Stelle einschleichen.
Das was dort erklärt wird ![]() kann man teilweise auch in Delphi nutzen. Nur ob das mit dem "automatischen" Bindestrich im Delphi klappt, weiß ich nicht, also z.B. bei dem #$8203 ( <wbr> ). ![]() NonBreakingSpace = #160 |
AW: WordBreak innerhalb eines Wortes
Ich hab mal was geschrieben, ist aber schon lange her, so dass ich es dir nicht erklären kann. Gedacht ist es so, dass ein beliebiger Text einer StringList so umbrochen wird, dass er von der Breite in eine von der Breite vordefinierte Bitmap passt. Die Höhe der Bitmap sollte dann auch noch neu definiert werden bevor gezeichnet wird:
Delphi-Quellcode:
//Bricht die Textzeilen eines Textes in StringList so, dass sie in einer
//Bitmap passen. Diese Prozedur bricht nur die Zeilen, zeichnet nicht. //Der Bitmap-Parameter dient nur zur Größenbestimmungen: Font, Width, usw. //List enthällt den Text der umbrochen werden soll. procedure TextToBitmap2(AList: TStrings; ATarget: TBitmap); var i, k, LastSpace: Integer; Line, s: String; begin if AList.Count = 0 then Exit; if ATarget.Width = 0 then Exit; i := 0; repeat LastSpace := 0; for k := 1 to Length(AList[i]) do begin Line := AList[i]; if (ATarget.Canvas.TextWidth(Copy(Line, 1, k))) <= (ATarget.Width) then begin if {Line[k]} Copy(Line, k, 1) = ' ' then LastSpace := k; end else begin if LastSpace = 0 then begin if k > 0 then begin s := Copy(Line, k, Length(Line)); //Schneidet ab letzten gültigen Zeichen ab System.Delete(Line, k, Length(Line)); end; end else begin //Mit +1 wird das Leerzeichen nicht übernommen, da es sonst als //erstes Zeichen in der Zeile vorkommt s := Copy(Line, LastSpace+1, Length(Line)); //Mit +1 bleibt das Leerzeichen an der aktuellen Zeile, //was bei Übertragung in Grafik nicht wichtig ist. //Mit +0 (oder Nichts) wird auch das Leerzeichen gelöscht System.Delete(Line, LastSpace+1, Length(Line)); end; AList[i] := Line; AList.Insert(i + 1, s); end; end; Inc(i); until i > (AList.Count - 1); end; |
AW: WordBreak innerhalb eines Wortes
Ich würde anstatt einem Bitmap einen Canvas und die Breite übergeben; das ist einfach flexibler.
Weil dann auch der Prozedurname nicht mehr passt würde ich vorschlagen:
Delphi-Quellcode:
procedure LimitLineWidths(AList: TStrings; Canvas:TCanvas; Width:Integer);
var ... |
AW: WordBreak innerhalb eines Wortes
Das Ergebnis landete bei mir direkt in einer Bitmap, deshalb die Lösung. Technisch gesehen kann man es auch mit Canvas machen. Width kann man aus ClipRect.Right - ClipRect.Left ermitteln.
|
AW: WordBreak innerhalb eines Wortes
Zitat:
Vielleicht möchte man links und rechts einen Rand freihalten oder gar 2-spaltig ausgeben. Mit meinem Vorschlag hält man sich alle Möglichkeiten offen... |
AW: WordBreak innerhalb eines Wortes
Danke schon mal für Euren Input. Ich habe es nun folgendermaßen gelöst:
Delphi-Quellcode:
Vielleicht hilft es ja dem ein oder anderen. Das Image32 aus der GR32 kann natürlich auch ein normales Bitmap sein.
var n, t: String; r: TRect; ts: TSize;
a, h: Integer; TempList: TStringList; n := 'Normaler Text und DerSuperlangeTextDerUmgebrochenWerdenMuss'; r := Rect(0, 0, 180, 0); // über 180 Pixel wird umgebrochen h := DrawText(Image32.Bitmap.Handle, PChar(n), Length(n), r, DT_WORDBREAK or DT_NOPREFIX or DT_CALCRECT); if r.Right > 180 then begin // ein einzelnes Wort ging über 180 Pixel hinaus TempList.Text := WrapText(n, 10); // alles was länger ist als 10 Zeichen bekommt eine eigene TStringGrid-Zeile for a := 0 to Pred(TempList.Count) do begin t := TempList[a]; // Text zeilenweise untersuchen DrawText(Image32.Bitmap.Handle, PChar(t), Length(t), r, DT_WORDBREAK or DT_NOPREFIX or DT_CALCRECT); if r.Right > 180 then begin n := ''; // ein überlanges Wort wurde gefunden while Length(t) > 0 do begin GetTextExtentExPoint(Image32.Bitmap.Handle, PChar(t), Length(t), 180, @h, nil, ts); n := n + Copy(t, 1, h) + ' '; Delete(t, 1, h); end; TempList[a] := n; end; r := Rect(0, 0, 180, 0); end; n := StringReplace(Trim(TempList.Text), #13#10, '', [rfReplaceAll]); // nicht ausführen falls CRs gewünscht h := DrawText(Image32.Bitmap.Handle, PChar(n), Length(n), r, DT_WORDBREAK or DT_NOPREFIX or DT_CALCRECT); end; Image32.Textout(r, DT_WORDBREAK or DT_NOPREFIX, n); |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:33 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz