Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Font, tatsächliche breite eines Buchstaben ermitteln?


ALF - Di 02.11.10 19:11
Titel: Font, tatsächliche breite eines Buchstaben ermitteln?
Meine Frage ziehlt darauf, das ich Text automatisch mit (Zeilenumbruch) versehen möchte, den ich auf einer Fläsche darstelle. Problem dabei ist die tatsächliche Breite eines Buchstaben zu erkennen!
zB "B" ist etwa dreimal so breit als "i" . Dadurch kann ich leider den Umbruch nicht genau bestimmen.
Meine Frage nun. Gibt es ne Möglichkeit dies zu errechen? Denn Font.Size sagt ja nichts über die tatsächliche Breite eines Buchstaben aus.

Gruss Alf


elundril - Di 02.11.10 19:13

Mittels Canvas.TextWidth(); kannst du die breite einer zeichenkette ermitteln.

lg elundril


ALF - Di 02.11.10 19:32

Ähm, bevor ich zeichne?
Der Text wird ja erst in einem Edit eingetragen und dann auf die Fläsche übertragen, wie soll ich das ermitteln?
Hier mal mein Code wie ich es jetzt mache:

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:
var
     S: String;
     Ss: Array[0..3of String;
     X, Y, Fi, Ls, I : Integer;
begin
    Y:= 0;
    S:= FGaugeCoText;                   //<---- in dieser Variablen steht der Text
    Fi:= (Width div (Font.Size-4)+1);   //<---- hier teile ich die breite der Fläsche durch Font.Size
    Ls:= length(S) div Fi;              //<---- wieviele Zeilen ich benötige 

    for I:= 0 to Ls do
    begin
        Ss[i]:= TrimLeft(LeftBStr(S, Fi)); 
        Delete(S, 1, Fi);
    end;
.....
.....
    if ShowText then
    for I:= 0 to ls do
    begin
        X:= PaintRect.Left + Font.Size * 4;
        if I = 0 then
           Y:= PaintRect.Top + 24
        else
           Y:= Y + Font.Size + 4;

       TextRect(PaintRect, X, Y, Ss[I]);
       AnImage.Canvas.Draw(00, OverRect);//<--- hier wird er erst gezeichnet
    end;
.......


Gruss Alf


elundril - Di 02.11.10 19:51

folgendes:


Delphi-Quelltext
1:
breite := AnImage.Canvas.TextWidth(S);                    


Das kannst du direkt unter die Zeile S := FGaugeCoText; schmeißen. Canvas.TextWidth zeichnet ja nix, es misst nur. Das heißt, selbst wenn du gar keine Textausgabe hättest, könntest du das einsetzen.

lg elundril


jaenicke - Di 02.11.10 19:51

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
Ähm, bevor ich zeichne?
Ja, genau.

Es wird an Hand der gesetzten Einstellungen deiner Leinwand die Breite ermittelt, genau darum geht es dir doch. Ob du da schon was gezeichnet hast, hat damit ja nichts zu tun. Windows muss das nicht durch echtes Zeichnen ausprobieren wie breit es denn wird. :mrgreen:


ALF - Di 02.11.10 20:30

Chick, habe es verstanden, bin auch schon dabei das ganze umzuschreiben, nur der Zeilenumbruch mhhhh... da muss ich mir was neues ausdenken. Der funct natürlich so nicht mehr :?
Ich weiss ja nicht an welcher TextStelle der nun ist!??

Gruss ALf


jaenicke - Di 02.11.10 20:51

Lass doch das Umbrechen einfach automatisch machen. :nixweiss: DrawText mit DT_WORDBREAK und fertig. Ggf. noch vorher mit DT_CALCRECT das Zielrechteck ausrechnen lassen.

Und Canvas.TextRect sollte das auch können.


ALF - Di 02.11.10 21:07

Jo, wenn mans weiss ist es schön. Ich muss doch erst mal das alte Konzept aus den Gedanken löschen. Weil, es sind 2 unterschiedlich Texte in der Procedure. Einmal normales Caption und dann ebend noch der CoText. Beide werden aber in der gleichen Procedure angezeigt. Und, ich bin nun mal kein Schnelldenker :mrgreen:
Werd aber mit Deinen Hinweisen hoffentlich was anfangen können! Mal sehen wie weit ich komme.

Gruss ALf


ALF - Mi 03.11.10 12:47

Sorry, sind zwar erst 15h rum, möchte nur mitteilen wie ich es jetzt gelöst habe.
1. Alle gefundenen Beispiele mit DrawText, hier und anderswo, sei es auf einem Label oder in einem Image, konnte ich einfach nicht umsetzten! Es wurde nie eine neue Zeile gezeichnet :nixweiss:
2. Habe ich mir gedacht, wie würde DrawText das den intern lösen? Ergo selbst ist der man :wink:

Unter Berücksichtigung des vorhanden, habe ich es jetzt so umgesetzt


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:
procedure TGaugeButton.PaintAsText(AnImage: TBitmap; PaintRect: TRect);
var
   S: String;
   Ss: Array[0..2of String;
   X, Y, Ls, I: Integer;
   OverRect: TBltBitmap;
   TempFont: TFont;
begin
    Y:= 0;
    ls:= 0;

    OverRect:= TBltBitmap.Create;
    try
        OverRect.Width:= AnImage.Width;
        OverRect.Height:= AnImage.Height;
        OverRect.TransparentMode:= tmAuto;
        OverRect.Transparent:= True;
        with OverRect.Canvas do
        begin
            Font:= Self.Font;
            TextRect(PaintRect, PaintRect.Left + 2, PaintRect.Top, FGaugeCaption);
            AnImage.Canvas.Draw(00, OverRect);

            if ShowText then
            begin
                X:= PaintRect.Left + Font.Size * 3;
                Tempfont:= Self.Font;
                Font:= Self.FCoTextFont;
//----------------- hier das was DraText vom Prinzip auch machen würde  ----------------
                for I:= 1 to length(FGaugeCoText) do
                begin
                    S:= S + copy(FGaugeCoText, I, 1);
                    Ss[Ls]:= TrimLeft(S); //<----nur diese ebend nicht, Leerzeichen am Anfang der Zeile entfernen
                    if OverRect.Canvas.TextWidth(Ss[Ls]) > OverRect.Width - X - Font.Size - FBorderWidth then
                    begin
                        S:= '';
                        inc(Ls);
                        if Ls > 2 then break;
                    end
                end;
//------------------------- DrawText zuende   --------------------------------------------
                for I:= 0 to high(Ss) do
                begin
                    if I = 0 then
                       Y:= PaintRect.Top + 22
                    else
                       Y:= Y + Font.Size + 4;

                    TextRect(PaintRect, X, Y, Ss[I]);
                    AnImage.Canvas.Draw(00, OverRect);
                end;
            end;
            Font:= TempFont;
        end;
    finally
        OverRect.Free;
    end;
end;

Ich weiss...., ist nicht die engl. Art zu Coden. Aber bevor ich mein ganzes Paint umändere, um DrawText doch nicht zugebrauchen wegen evtl Leerzeichen am Anfang der neuen Zeile, dürfte dies sicherlich ne Alternative sein :mrgreen:

THX an Euch.

Gruss Alf