Autor Beitrag
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: So 18.02.18 04:29 
Hallo Forum

Problemstellung:
Mit der Methode DrawText() zeichne ich die Beschriftung auf mein Steuerelement, die je nach Alignment/Ausrichtung entsprechend dargestellt wird:

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:
type
  TAlignment = (taLeftJustify, taRightJustify, taCenter); // von Delphi deklariert
  TBoxAlignment = (baLeft, baTop, baRight, baBottom); // von mir


// wird in Paint() aufgerufen
procedure TfrCheckRadioControl.DrawCaption(const AText: string);
var
  textHeight: Integer;
  rText: TRect;
  uFormat: DWord;
begin
  textHeight := Canvas.TextHeight(AText);
  uFormat := 0;

  case BoxAlignment of
    baTop:
      rText := Rect(0, BoxSize + 3, Width, BoxSize + 3 + textHeight);

    baRight:
      rText := Rect(0, (Height - textHeight) div 2, Width - BoxSize - 3,
                    textHeight + (Height - textHeight) div 2);
    baBottom:
      rText := Rect(0, Height - BoxSize - 3 - textHeight,
                    Width, Height - BoxSize - 3);
    else
      rText := Rect(BoxSize + 3, (Height - textHeight) div 2,
                    Width, textHeight + (Height - textHeight) div 2);
  end;

  case Alignment of
    taRightJustify:
      uFormat := uFormat or DT_RIGHT;
    taCenter:
      uFormat := uFormat or DT_CENTER;
    else
      uFormat := uFormat or DT_LEFT;
  end;

  //if WordWrap then
  //  uFormat := uFormat or DT_WORDBREAK;

  DrawText(Canvas.Handle, @AText[1], Length(AText), rText, uFormat);
end;

delphi_zeilenumbruch

Im Anschluss bräuchte ich noch einen Zeilenumbruch, der bei zu langen Beschriftungen, wortweise den Text umbricht.
Wie genau das nun erfolgt, ist mir leider nicht ganz klar.
In anderen Beispielen sehe ich, dass dabei zuerst das TextRect, also die genauen Abmaße des Textes wie folgt ermittelt werden:

ausblenden Delphi-Quelltext
1:
DrawText(Canvas.Handle, @sText[1], Length(sText), TextRect, DT_CALCRECT);					

Das TextRect wird dann mit dem ClientRect des Controls verglichen, eins wird auf das andere angepasst, was mir ebenso unklar ist, und dann wird DrawText() erneut ausgeführt mit:

ausblenden Delphi-Quelltext
1:
DrawText(Canvas.Handle, @sText[1], Length(sText), TextRect, DT_WORDBREAK or MyFormat);					

Wie muss nun die Anpassung für das "TextRect" im Prinzip aussehen, um den gewünschten Zeilenumbruch einleiten zu können?
Einloggen, um Attachments anzusehen!
_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Symbroson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: So 18.02.18 22:44 
Erstmal gibt es eine spezielle Methode namens canvas.TextWidth(const text: String): integer; mit der du die Textbreite ermitteln kannst.

Um nun die richtige Position für deinen Zeilenumbruch zu finden würde ich eine Art binäre Suche anwenden.
Du musst dir zunächst ein paar Zeichen(ketten) heraussuchen, an denen du Zeilenumbrüche erlaubst (typischerweise ein Space/Leerzeichen, und diese Positionen im Text in einem extra Feld speichern. Dann gehst du da mit deiner binären Suche durch und suchst die Position heraus, an der der Text maximal lang, aber immernoch zur Canvas/Boxbreite passt - je nachdem, in welches Rechteck dein Text geschrieben werden soll.
Danach machst du einfach mit dem verbleibenden Text weiter, bis irgendwann die Breite des verbleibenden Textes kleiner als das deiner Box ist.

Die einzelnen Zeilen musst du noch immer einzeln per DrawText Zeichnen. Für die y-Position nimmst du einfach y0 - Zeile * Font.Height. Minus, weil Font.Height meist negativ ist.

Hoffe, das hilft dir weiter :)

LG

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: So 18.02.18 23:49 
Die "spezielle Methode" ist nicht notwendig.
Im errechneten TextRect ergibt sich die Textbreite mit: TextRect.Right - TextRect.Left;
DrawText() zeichnet mit DT_WORDBREAK einen umgebrochenen Text. Davor muss aber das TextRect entsprechend angepasst werden.
Die Frage ist immer noch, wie dieses TextRect auszusehen hat, bevor ich mit DrawText() und DT_WORDBREAK den Zeilenumbruch ausführe?

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Symbroson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Mo 19.02.18 00:14 
Schade - Naja, falls du es doch nicht rausbekommen solltest, gäbe es wenigstens noch ne Idee, wie du es selbst implementieren könntest. Ich mag sowas eher ^^

Es sieht für mich nicht so aus, als ob dieses TextRect irgendeinen Einfluss auf den Text Hat (bis auf die Position)
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure TForm1.Button1Click(Sender: TObject);
var sText: string;
  TextRect: TRect;
begin
  sText := 'hello world! I need some more characters.';
  TextRect := Rect(20,20,70,70);
  Canvas.Rectangle(TextRect);
  DrawText(Canvas.Handle, @sText[1], Length(sText), TextRect, DT_CALCRECT);
  DrawText(Canvas.Handle, @sText[1], Length(sText), TextRect, DT_WORDBREAK);
end;

Ich kann dir da leider nicht weiterhelfen

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Symbroson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Mo 19.02.18 00:17 
DTWordBreak scheint lediglich \r\n sequenzen im String Selbst zu behandeln, wenn zB sText := 'hello world! I need'#13#10'some more characters.';wird der Zeilenumbruch auch gezeichnet.

[entschuldigung - hätte ich in den vorherigen Post schreiben können]

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mo 19.02.18 00:36 
Nein. Der Wert DT_WORDBREAKS sorgt für einen Zeilenumbruch, wenn "sText" breiter oder höher als der Bereich "TextRect" ist:
Zitat:
Breaks words. Lines are automatically broken between words if a word would extend past the edge of the rectangle specified by the lpRect parameter.


Außerdem:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var sText: string;
begin
  sText := 'hello world! I need some more characters.';
  DrawText(Canvas.Handle, @sText[1], Length(sText), TextRect, DT_CALCRECT); 
  ShowMessage(IntToStr(TextRect.Right - TextRect.Left));
end;

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Symbroson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Mo 19.02.18 00:46 
ach ja klar, das MeasureText hat mein TextRect verändert. Dann geht es auch.
textBox
Und wo genau ist jetzt das Problem? Das MeasureText lässt du einfach weg und ersetzt es durch das Rect in den dein Text geschrieben werden soll. Vmtl relativ zum Komponentenursprung (Left, Right).
Einloggen, um Attachments anzusehen!
_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mo 19.02.18 00:54 
Hab vielen Dank. Der umrahmte Text bringt mich schon weiter. :zustimm:

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Symbroson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Mo 19.02.18 00:55 
Ok, Schön wenn ich dir irgendwie helfen konnte :zwinker: :lol:

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mo 19.02.18 10:43 
Den Zeilenumbruch bekomme ich so nun hin:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
//...
if WordWrap then
begin
  uFormat := uFormat or DT_WORDBREAK;
  rText.Bottom := Height;
end;

DrawText(Canvas.Handle, @AText[1], Length(AText), rText, uFormat);

Probleme macht einzig noch die Box- und Textausrichtung nach unten (BoxAlignment := baBottom):

delphi_zeilenumbruch2

Hier wird der Text über die Box gemalt. Den Text muss ich nun irgendwie von unten nach oben zeichnen, ohne die Ausgangsposition zu ändern, wo der Text nicht zu lange ist.

Nachtrag

Mit dem Wert DT_BOTTOM geht es schonmal nicht, außerdem kann man ihn auch nicht mit DT_WORDBREAK kombinieren.
Dann lautet die Lösung eben:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
if WordWrap then
begin
  uFormat := uFormat or DT_WORDBREAK;
  if BoxAlignment <> baBottom then
    rText.Bottom := Height;
end;

DrawText(Canvas.Handle, @AText[1], Length(AText), rText, uFormat);

So wird schonmal nichts übermalt.


Das Thema hat sich erledigt !!!
Einloggen, um Attachments anzusehen!
_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)