How do I change text size and fonts?

How can I change text size and fonts. Change color works fine. Any examples? Win32 GUI program. Borland C++ ver 5.03 compiler.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class WriteText
{
public:

    HDC hdc;
    PAINTSTRUCT ppaint;

    WriteText(int _Xpos, int _Ypos, char *_szMessage)
    {
        hdc = BeginPaint(hWnd, &ppaint);
        //SetTextColor(hdc, RGB(0,0,0));
        TextOut(hdc, _Xpos, _Ypos, _szMessage, strlen(_szMessage));
        EndPaint(hWnd, &ppaint);
    }
};
You want SelectObject() after CreateFont(), see MSDN for GDI related functions.
Thanks. Can all this be done before call to BeginPaint like an initialization?
Ok, so I have seen this incorrectly done enough number of times so I'll see if I can explain this.

Windows in Windows have two very similar window messages: WM_PAINT and WM_PRINT (well, and WM_PRINTCLIENT). WM_PAINT is the only one needed but it is strongly recommended that you also implement the others. For example, the animation that occurs on top level windows when they are minimized require that the window correctly processes WM_PRINT and WM_PRINTCLIENT.

The painting procedure on both WM_PAINT and WM_PRINTCLIENT is the same, except that on processing of the latter you must paint the whole client area, not just the invalidated parts. Therefore what is recommended is that you have a separate drawing function that receives as argument the device context to use. Like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void DrawWindow(HDC hDC);

...
//In the Window procedure:
case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hDC = BeginPaint(hWnd, &ps);
    DrawWindow(hDC);
    EndPaint(hWnd, &ps);
}
break;
case WM_PRINTCLIENT:
{
    DrawWindow(reinterpret_cast<HDC>(wParam));
}
break;


If you move the calls to BeginPaint() and EndPaint() outside the window procedure, then you cannot reutilize your drawing routine and you will have to duplicate drawing code to also implement WM_PRINTCLIENT.
Can all this be done before call to BeginPaint like an initialization?

Assuming you're talking about creating the font and calling SelectObject(), the answer is yes and no.

You can create the font up front and hold onto it.

But you can only call SelectObject at the point that you need to use the font. And when you've finished using it, you must restore the display device context to its previous state.

Where (a) I've picked up webJose's change (the WM_PAINT handler calls BeginPaint, etc), and (b) converted your WriteText constructor into a method (you keep an instance of the writer around to avoid repeatedly recreating the font).

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
const COLORREF colorRed = RGB(255, 0, 0);

class TextWriter
{
private:

    HFONT hfont;
    COLORREF textColor;

public:

    TextWriter() : hfont(NULL), textColor(colorRed)
    {
        // initialize font here (I prefer CreateFontIndirect to CreateFont,
        // as it's easier to deal with unused params using memset.)
        LOGFONT logFont;
        memset(&logFont, 0, sizeof(logFont));
        logFont.lfHeight = -48; // see PS
        logFont.lfWeight = FW_BOLD;
        strcpy(logFont.lfFaceName, "Broadway");
        hfont = CreateFontIndirect(&logFont);
    }

    ~TextWriter()
    {
        DeleteObject(hfont);
    }

    void WriteText(HDC _hdc, int _Xpos, int _Ypos, char *_szMessage)
    {
        // set text color and font
        COLORREF oldTextColor = SetTextColor(_hdc, textColor);
        HFONT oldHFont = (HFONT)SelectObject(_hdc, hfont);

        TextOut(_hdc, _Xpos, _Ypos, _szMessage, strlen(_szMessage));

        // restore text color and font
        SetTextColor(_hdc, oldTextColor);
        SelectObject(_hdc, oldHFont);
    }
};


Andy

PS from MSDN (LOGFONT's lfHeight member):

> 0 The font mapper transforms this value into device units and matches it against the cell height of the available fonts.
0 The font mapper uses a default height value when it searches for a match.
< 0 The font mapper transforms this value into device units and matches its absolute value against the character height of the available fonts
Last edited on
Thanks Andy. I'm new to Win32 GUI programming and try to get an understanding how it works. Done "C" for decades but C++ GUI programming is totally new to me. I made a program already in Win32 GUI that do the powerball numbers by random for the fun of it and it works fine. I would like to change the font and size of the numbers that's why I'm asking. Your example is very good and explain a lot but I have one question. What is logFont? As I see it it's a pointer to the font used. Am I correct?
Last edited on
@andy: Great and simple modification. Kudos.

@Perman: LOGFONT can be found via Google. It is a structure that contains different properties of the font that you are requesting. You see, fonts are categorized and can have effects like underline, bold, etc. Using a LOGFONT structure you can specify all these neat properties.
Use CreateFont if you don't want to use LOGFONT structure, but takes a very long list of arguments :)
As webJose and modoran have already said. LOGFONT is a struct which describes the font you want to create. You can also get the details of an existing font back using GetObject()

1
2
3
    LOGFONT logFont;
    memset(&logFont, 0, sizeof(logFont));
    GetObject(hfont, sizeof(logFont), &logFont);


And as modoran also said, the function CreateFont has loads of parameters. From the MSDN entry:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HFONT CreateFont(
  __in  int nHeight,
  __in  int nWidth,
  __in  int nEscapement,
  __in  int nOrientation,
  __in  int fnWeight,
  __in  DWORD fdwItalic,
  __in  DWORD fdwUnderline,
  __in  DWORD fdwStrikeOut,
  __in  DWORD fdwCharSet,
  __in  DWORD fdwOutputPrecision,
  __in  DWORD fdwClipPrecision,
  __in  DWORD fdwQuality,
  __in  DWORD fdwPitchAndFamily,
  __in  LPCTSTR lpszFace
);


So I could have used

1
2
hfont = CreateFont( -48, 0, 0, 0, FW_BOLD, 0,
    0, 0, 0, 0, 0, 0, 0, "Broadway");


Or if I wanted to spell it out more fully

1
2
3
4
hfont = CreateFont(-48, 0, 0, 0, FW_BOLD, FALSE,
    FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
    CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
    "Broadway");


But FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, etc all have a value of 0

Which is why I prefer CreateFontIndirect. It takes just the one parameter, the address of a LOGFONT struct, which allows you not only to specify all the same information but can be zeroed to set all the default values in one go.

Last edited on
Thanks Andy for your help. It works great. I change it around a little to a couple of function calls that create the font and the color. Just what I wanted.
Thanks again for your help and simple way to explain it.
Per
Topic archived. No new replies allowed.