Autor Beitrag
Daniel L.
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: Mi 27.10.10 17:29 
Hallo!

Kann man die Länge in Pixel einer formatierten Textzeile in einer RichEdit bestimmen?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
with RichEdit do
begin
    SelAttributes.Color := clred;
    SelAttributes.Size := 20;
    Paragraph.Alignment := taCenter;
    Lines.Add('Wie lang ist eigentlich diese Zeile in Pixeln');
end;


Schon mal Danke + Gruss: Daniel
elundril
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3747
Erhaltene Danke: 123

Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
BeitragVerfasst: Mi 27.10.10 18:23 
Mittels Canvas.TextWidth;

hier ein beispiel:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  var bmp := TBitmap;
begin
  bmp := TBitmap.Create();
  bmp.canvas.Font := Richedit1.Font;
  laenge := bmp.canvas.textwidth(deine_Zeile);
  bmp.free
end;


das noch mit entsprechenden Ressourcenschutzblöcken ausstatten und voilá!

lg elundril

_________________
This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19321
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 27.10.10 19:40 
In einem RichEdit kann der Text aber beliebig formatiert sein.

Ich vermute daher, dass du da manuell durchgehen musst und die Zeichen entsprechend ihrer Formatierung behandeln musst. Eine fertige Routine gibt es dafür AFAIK nicht.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Mi 27.10.10 23:50 
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
Kann man die Länge in Pixel einer formatierten Textzeile in einer RichEdit bestimmen?
Beispiel:
ausblenden 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:
26:
27:
procedure TMainform.Button1Click(Sender: TObject);
var
  PunktZeile  : TPoint;
  PunktAnfang : TPoint;
  CharPos     : integer;
begin
  CharPos := 0;
  SendMessage(RichEdit1.Handle, EM_PosFromChar, wParam(@PunktAnfang), lParam(CharPos));
  CharPos := SendMessage(RichEdit1.Handle, EM_LineLength, 00);
  SendMessage(RichEdit1.Handle, EM_PosFromChar, wParam(@PunktZeile), lParam(CharPos));
  Label1.Caption := 'Anzahl Zeichen: ' + IntToStr(CharPos);
  Label2.Caption := 'Breite der Zeile (Space + Text): ' + IntToStr(PunktZeile.X);
  Label3.Caption := 'Breite der Zeile (nur Text): '
    + IntToStr(PunktZeile.X - PunktAnfang.X + 1);
end;

procedure TMainform.Button2Click(Sender: TObject);
begin
  with RichEdit1 do
    begin
      Clear;
      SelAttributes.Color := clred;
      SelAttributes.Size := 20;
      Paragraph.Alignment := taCenter;   // ggf. zum Testen auskommentieren
      Lines.Add('Wie lang ist eigentlich diese Zeile in Pixeln?');
    end;
end;

Im Beispiel gehe ich von nur einer Zeile aus, also ggf. anpassen.

Edit1: Ob die Zeichenbreite des letzten Zeichens in den Werten eingerechnet ist, habe ich noch nicht geprüft.
@elundril: Deine Prozedur scheint falsche Werte zu liefern (203). Ich ermittele hingegen 509, was wohl eher hinkommen dürfte.

Edit2: Das letzte Zeichen ist mit eingerechnet, was man leicht überprüfen kann, wenn der Text aus nur einem Zeichen besteht.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19321
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 28.10.10 05:51 
Stimmt, auf die Idee bin ich gar nicht gekommen. Über die Position des ersten und letzten Zeichens lässt sich die Breite natürlich berechnen. :zustimm:
Daniel L. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: Do 28.10.10 09:12 
@Gerd: Vielen Dank für die kompetente Antwort!
Verrätst du mir noch, was ich anpassen muss, um z.B. die 3. Zeile zu 'messen'?

Danke + Gruss: Daniel
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19321
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 28.10.10 11:11 
CharPos musst du (bezogen auf das Beispiel) entsprechend setzen.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Do 28.10.10 13:14 
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
Verrätst du mir noch, was ich anpassen muss, um z.B. die 3. Zeile zu 'messen'?
Ich komme erst heute Nacht dazu, weiter zu programmieren. Jetzt stehen erst einmal zwei Stunden Gassigänge mit meiner verspielten Schäferhündin und ein längerer Zahnarztbesuch an.
Daniel L. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: Do 28.10.10 19:16 
hm, intern scheint TRichEdit für jede Textzeile 2 weitere Charakters dazuzuzählen (vielleicht #10 und #13 ?)

Folgende Funkion funzt bei mir:

ausblenden 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:
26:
27:
28:
29:
function TForm1.GetZeilenBreite (Zeile : integer) : integer;
var i, CharCount : integer;
    ZeileAnfang, ZeileEnde : TPoint;
begin

  if (zeile > (RichEdit1.Lines.Count - 1)) or (zeile < 0then
     begin
       result := -1;
       exit;
     end;

  CharCount := 0;

  for I := 0 to zeile - 1 do inc (CharCount, length (RichEdit1.Lines [i]) + 2);
      // erstmal die Zeichen der Zeilen davor zählen


  SendMessage (RichEdit1.Handle, EM_PosFromChar, wparam (@ZeileAnfang), CharCount);
  CharCount := CharCount  + SendMessage (RichEdit1.Handle, EM_LineLength, CharCount, 0);
  SendMessage(RichEdit1.Handle, EM_PosFromChar, wParam (@ZeileEnde), CharCount);
  result := ZeileEnde.X - ZeileAnfang.X;
end;

//-----------

procedure TForm1.Button1Click(Sender: TObject);
begin
   showmessage ('Zeilenbreite  = ' + Inttostr (GetZeilenBreite (1)));
end;


Ich hoffe, dass das auch programmiertechnisch in Ordnung ist und dass Gerd kein Zahnschmerzen hat :)

Gruss: Daniel
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19321
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 28.10.10 19:29 
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
Ich hoffe, dass das auch programmiertechnisch in Ordnung ist und dass Gerd kein Zahnschmerzen hat :)
Ich bekomm da immer eher Bauchschmerzen. :P

Zur Sache:
Du brauchst keine Schleife. Mit EM_LINEINDEX bekommst du das erste Zeichen einer Zeile:
msdn.microsoft.com/e...761611(v=VS.85).aspx
Steht alles in der Doku. ;-)

// EDIT:
Ach ja: Die beiden Zeichen pro Zeile mehr sind in der Tat die Zeilenumbruchszeichen.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Do 28.10.10 20:17 
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
Ich hoffe, dass das auch programmiertechnisch in Ordnung ist und dass Gerd kein Zahnschmerzen hat :)
Nö, keine Zahnschmerzen. Bin nur um ca. 3 Gramm Edelmetall wertvoller geworden (neue Zahnkrone). ;-)
Ich bin zur Zeit dabei, eine komfortable Funktion für die Aufgabe zu schreiben. Dazu brauche ich aber noch etwas Zeit (debuggen, testen usw.). Aber jetzt muß ich erst einmal wieder mit meiner Madame die Bäumchen im Park zählen und kontrollieren gehen. ;-)
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Do 28.10.10 23:51 
So, hier ist meine Lösung, die auch Zeilenumbrüche durch WordWrap richtig behandelt. Bitte beachten, daß die Funktion verschieden aufgerufen werden kann:
1. mit Zeile = - 1: liefert die Zeilenanzahl zurück
2. mit Zeilennummer, aber NurText = false: Breite der Zeichenkette plus dem Leerraum vor dem 1. Zeichen
3. mit Zeilennummer, aber NurText = true: Breite der Zeichenkette
NurText kann beim Aufruf weggelassen werden. Dann arbeitet die Funktion mit NurText = true

ausblenden volle Höhe 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:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

type
  TMainform = class(TForm)
    RichEdit1: TRichEdit;
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Button2: TButton;
    Label3: TLabel;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    function ErmittelnTextBreite(Handle : THandle; Zeile : integer;
             NurText : boolean = true): integer;
  end;

var
  Mainform: TMainform;

implementation

{$R *.dfm}

// Zeilenindex ist 0-basierend ---> 0 = 1. Zeile
function TMainform.ErmittelnTextBreite(Handle : THandle; Zeile : integer;
         NurText : boolean = true): integer;
var
  AnzZeilen      : integer;
  ErstesZeichen  : integer;
  LetztesZeichen : integer;
  PunktStart     : TPoint;
  PunktEnde      : TPoint;
begin
  Result := - 1;
  AnzZeilen := SendMessage(Handle, EM_GetLineCount, 00);

  // Anzahl der Zeilen zurückgeben, wenn Zeile = - 1,
  // sonst die Textbreite der Zeile ermitteln.

  if Zeile = - 1 then
    Result := AnzZeilen
  else
    begin
      ErstesZeichen := SendMessage(Handle, EM_LineIndex, wParam(Zeile), 0);
      LetztesZeichen := SendMessage(Handle, EM_LineLength, wParam(ErstesZeichen), 0);
      SendMessage(Handle, EM_PosFromChar, wParam(@PunktStart), lParam(ErstesZeichen));
      SendMessage(Handle, EM_PosFromChar, wParam(@PunktEnde), lParam(ErstesZeichen + LetztesZeichen));

      // Zeilenumbruch durch WordWrap abfangen

      if PunktStart.Y <> PunktEnde.Y then     // Zeilenumbruch?
        SendMessage(Handle, EM_PosFromChar, wParam(@PunktEnde),
          lParam(ErstesZeichen + LetztesZeichen - 1));

      // Ergebnis zurückgeben

      if NurText then
        Result := PunktEnde.X - PunktStart.X + 1
      else
        Result := PunktEnde.X;
    end;
end;

procedure TMainform.Button1Click(Sender: TObject);
var
  Zeile     : integer;
  AnzZeilen : integer;
  Breite    : integer;
begin
  if not TryStrToInt(Trim(Edit1.Text), Zeile) then
    ShowMessage('Fehler: Keine Ziffer im Edit-Feld!')
  else
    begin
      AnzZeilen := ErmittelnTextBreite(RichEdit1.Handle, - 1);
      Label1.Caption := 'Anzahl Zeilen: ' + IntToStr(AnzZeilen);
      if Zeile > (AnzZeilen - 1then
        ShowMessage('Fehler: RichEdit enthält nicht so viele Zeilen!')
      else
        begin
          Breite := ErmittelnTextBreite(RichEdit1.Handle, Zeile, false);
          Label2.Caption := 'Breite (Space am Angfang + Text): ' + IntToStr(Breite);
          Breite := ErmittelnTextBreite(RichEdit1.Handle, Zeile);
          // alternativ:
          //   Breite := ErmittelnTextBreite(RichEdit1.Handle, Zeile, true);
          Label3.Caption := 'Breite (nur Text): ' + IntToStr(Breite);
        end;
    end;

end;

procedure TMainform.Button2Click(Sender: TObject);
var
  Text1 : string;
  Text2 : string;
begin
  Text1 := 'Wie lang ist eigentlich diese Zeile in Pixeln?';
  Text2 := Text1 + Text1 + Text1;
  with RichEdit1 do
    begin
      Clear;
      SelAttributes.Color := clred;
      SelAttributes.Size := 20;
      Paragraph.Alignment := taCenter;   
      Lines.Add(Text1);
      SelAttributes.Color := clred;
      SelAttributes.Size := 20;
      Paragraph.Alignment := taCenter;
      Lines.Add(Text2);
      SelAttributes.Color := clred;
      SelAttributes.Size := 20;
      Paragraph.Alignment := taLeftJustify;
      Lines.Add(Text1);
      SelAttributes.Color := clred;
      SelAttributes.Size := 20;
      Paragraph.Alignment := taRightJustify;
      Lines.Add(Text1);
    end;
end;

end.

Edit1: Fehler in Zeile 89 korrigiert
Daniel L. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: Fr 29.10.10 09:39 
Oh ja, stimmt, ohne die WordWrap Beachtung kämen ja ggf. falsche Werte raus.

EM_GetLineCount scheint immer eine um 1 grössere Zahl zu liefern, man muss also wieder 1 subtrahieren, oder man nimmt Richedit.lines.count

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:

ausblenden Delphi-Quelltext
1:
2:
    if NurText then
        Result := PunktEnde.X - PunktStart.X + 1



Bist du sicher, dass das stimmt?
Für eine leere Textzeile kommt dann 1 raus!


Gruss: Daniel
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Fr 29.10.10 11:47 
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
EM_GetLineCount scheint immer eine um 1 grössere Zahl zu liefern, man muss also wieder 1 subtrahieren, oder man nimmt Richedit.lines.count

Das ist so nicht richtig. Es sind zwar z. B. 6 Zeilen mit Text vorhanden, aber es gibt noch eine 7. (leere) Zeile, in die Du mit dem Cursor springen kannst. Wenn Du in dieser Leerzeile die Backspace-Taste drückst, so daß der Cursor in der vorhergehenden Zeile direkt hinter dem Text steht, erst dann stimmen die Werte von Richedit.lines.count und EM_GetLineCount überein.
Zitat:
ausblenden Delphi-Quelltext
1:
2:
    if NurText then
        Result := PunktEnde.X - PunktStart.X + 1


Bist du sicher, dass das stimmt?
Für eine leere Textzeile kommt dann 1 raus!
Folgender Fall:
Eine Zeile ist linksbündig (taLeftJustify) ausgerichtet. Ohne "+ 1" ergäben sich dann folgende Werte für den String:
Nur Text: 508
aber Text plus Leerraum davor: 509
Das ist jetzt Auslegungssache, ob man das Pixel vor dem Text zur Textbreite hinzuzählt oder nicht. Du kannst das "+ 1" weglassen oder alternativ die Funktion am Ende um folgende Anweisung ergänzen:
ausblenden Delphi-Quelltext
1:
2:
if Result = 1 then
  Result := 0;
Das überlasse ich Dir. Ist wie gesagt eine reine Interpretationssache.