AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

WordBreak innerhalb eines Wortes

Ein Thema von SittingDuck · begonnen am 14. Nov 2012 · letzter Beitrag vom 17. Nov 2012
Antwort Antwort
SittingDuck

Registriert seit: 11. Jan 2006
Ort: Leverkusen
159 Beiträge
 
Delphi 2010 Professional
 
#1

WordBreak innerhalb eines Wortes

  Alt 14. Nov 2012, 15:50
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 hier besprochen. Wahrscheinlich brauche ich das Rad gar nicht neu zu erfinden, deshalb möchte ich mal Fragen, ob schon jemand einen ersten Ansatz vorweisen kann ... nur um nicht komplett bei Null anfangen zu müssen.

Danke schon mal für Eure Hilfe.
Ciao ... SittingDuck
iPhone Backup und mehr: iTwin v3.9 Beta ... Alternative Startleiste: Launcher v3.8 !
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: WordBreak innerhalb eines Wortes

  Alt 14. Nov 2012, 15:56
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
http://de.selfhtml.org/html/text/zeilenumbruch.htm
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> ).

Bei Google suchenZero Width
NonBreakingSpace = #160
$2B or not $2B

Geändert von himitsu (14. Nov 2012 um 15:58 Uhr)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#3

AW: WordBreak innerhalb eines Wortes

  Alt 14. Nov 2012, 17:01
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;
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#4

AW: WordBreak innerhalb eines Wortes

  Alt 14. Nov 2012, 17:26
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
  ...
Andreas
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#5

AW: WordBreak innerhalb eines Wortes

  Alt 14. Nov 2012, 17:43
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.
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#6

AW: WordBreak innerhalb eines Wortes

  Alt 14. Nov 2012, 18:20
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.
Nicht immer soll der mehrzeilige Text so breit sein wie das Ziel (Bitmap bzw. Canvas) und das Ziel muss nicht unbedingt ein Bitmap sein (könnte auch der Canvas von TPrinter sein).
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...
Andreas
  Mit Zitat antworten Zitat
SittingDuck

Registriert seit: 11. Jan 2006
Ort: Leverkusen
159 Beiträge
 
Delphi 2010 Professional
 
#7

AW: WordBreak innerhalb eines Wortes

  Alt 17. Nov 2012, 04:00
Danke schon mal für Euren Input. Ich habe es nun folgendermaßen gelöst:
Delphi-Quellcode:
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);
Vielleicht hilft es ja dem ein oder anderen. Das Image32 aus der GR32 kann natürlich auch ein normales Bitmap sein.
Ciao ... SittingDuck
iPhone Backup und mehr: iTwin v3.9 Beta ... Alternative Startleiste: Launcher v3.8 !
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:56 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz