PDA

View Full Version : How do you set the font for use with TextOut onto a surface?



Gadget
19-01-2003, 07:22 PM
I am writting text to a DirectX surface and can't seem to change the font...

Any ideas?

Alimonster
19-01-2003, 08:04 PM
If you're using some_surface.GetDC/TextOut/some_surface.ReleaseDC then you can use the stanard GDI functions. In this case, you want to fill out a TLogFont structure. There are a lot of options here for the font name, size, style, and so on -- too many to explain, so have a look at the LOGFONT structure in win32.hlp for more info (as a side note: you can rotate text using the lfOrientation and lfEscapement fields, which is a nice bonus). You then create the font from the LogFont structure using CreateFontIndirect, which returns a HFONT to your new GDI object. You select the object into the DC, draw your text, and select old font back. Something like this [untested]:

[background=#FFFFFF][comment=#0000FF][normal=#000000]
[number=#C00000][reserved=#000000][string=#00C000]var
FontDesc: TLogFont;
OldFont: HFONT;
NewFont: HFONT;
DC: HDC;
TheText: String;
begin
TheText := 'blah blah blah';

your_surface.GetDC(DC);

with FontDesc do
begin
lfHeight := 12;
lfWidth := 0;
lfEscapement := 0;
lfOrientation := 0;
// and so on for all the rest of the fields!
//...
end;

// create a new font based on the description above
NewFont := CreateFontIndirect(FontDesc);

// use the new font - we select it into the DC and grab the
// the return value, which is the old font
OldFont := SelectObject(DC, NewFont);

SetBKMode(DC, TRANSPARENT);

TextOut(DC, x, y, PChar(TheText), Length(TheText));

// restore the old font
SelectObject(DC, OldFont);
DeleteObject(NewFont);

your_surface.ReleaseDC(DC);
end;

(Consider adding try..finally blocks above if appropriate, of course.)

The above code demonstrates why the GDI sucks ass ;). If you're already using the VCL then you could probably create and use a TCanvas, making your life simpler. Dunno if it'll work like this, but try it anyway:

[background=#FFFFFF][comment=#0000FF][normal=#000000]
[number=#C00000][reserved=#000000][string=#00C000]var
Canv: TCanvas;
DC: HDC;
begni
Canv := TCanvas.Create;
your_surface.GetDC(DC);

Canv.Handle := DC;

// now use the canvas as normal!

Canv.Font.Name := 'Verdana';
Canv.Font.Size := 12;
Canv.TextOut(10, 20, 'roxx');

your_surface.ReleaseDC(DC);
Canv.Free;
end;
The above is untested and is only useful if you want to use the VCL (which you may or may not, due to the size increase).

Gadget
19-01-2003, 08:36 PM
If you're using some_surface.GetDC/TextOut/some_surface.ReleaseDC then you can use the stanard GDI functions. In this case, you want to fill out a TLogFont structure. There are a lot of options here for the font name, size, style, and so on -- too many to explain, so have a look at the LOGFONT structure in win32.hlp for more info (as a side note: you can rotate text using the lfOrientation and lfEscapement fields, which is a nice bonus). You then create the font from the LogFont structure using CreateFontIndirect, which returns a HFONT to your new GDI object. You select the object into the DC, draw your text, and select old font back. Something like this [untested]:

[background=#FFFFFF][comment=#0000FF][normal=#000000]
[number=#C00000][reserved=#000000][string=#00C000]var
FontDesc: TLogFont;
OldFont: HFONT;
NewFont: HFONT;
DC: HDC;
TheText: String;
begin
TheText := 'blah blah blah';

your_surface.GetDC(DC);

with FontDesc do
begin
lfHeight := 12;
lfWidth := 0;
lfEscapement := 0;
lfOrientation := 0;
// and so on for all the rest of the fields!
//...
end;

// create a new font based on the description above
NewFont := CreateFontIndirect(FontDesc);

// use the new font - we select it into the DC and grab the
// the return value, which is the old font
OldFont := SelectObject(DC, NewFont);

SetBKMode(DC, TRANSPARENT);

TextOut(DC, x, y, PChar(TheText), Length(TheText));

// restore the old font
SelectObject(DC, OldFont);
DeleteObject(NewFont);

your_surface.ReleaseDC(DC);
end;

(Consider adding try..finally blocks above if appropriate, of course.)

The above code demonstrates why the GDI sucks ass ;). If you're already using the VCL then you could probably create and use a TCanvas, making your life simpler. Dunno if it'll work like this, but try it anyway:

[background=#FFFFFF][comment=#0000FF][normal=#000000]
[number=#C00000][reserved=#000000][string=#00C000]var
Canv: TCanvas;
DC: HDC;
begni
Canv := TCanvas.Create;
your_surface.GetDC(DC);

Canv.Handle := DC;

// now use the canvas as normal!

Canv.Font.Name := 'Verdana';
Canv.Font.Size := 12;
Canv.TextOut(10, 20, 'roxx');

your_surface.ReleaseDC(DC);
Canv.Free;
end;
The above is untested and is only useful if you want to use the VCL (which you may or may not, due to the size increase).

Thanks for that ;) Worked a treat! I have now pretty much coded a dx replacement for that TRichEdit I was using. Just need to work out how to calculate the width of the text in bytes so I know when to wrap to the next line...

Alimonster
19-01-2003, 08:43 PM
The function TCanvas.TextWidth uses the API function "GetTextExtentPoint32" behind the scenes - it ought to do the trick.

Sly
19-01-2003, 11:08 PM
I would use DrawTextEx. You can pass a TRect to it and it will wrap the lines for you.

Gadget
20-01-2003, 01:59 PM
I would use DrawTextEx. You can pass a TRect to it and it will wrap the lines for you.

Thanks a lot guys :)

Will probably have to use DrawTextEx as the component doesn't have a Canvas.