0

I would like to draw text into a GDI device context DC using the same font but with different styles. I create a CFont object, select that font object into the DC and then I use DC.DrawText to draw text into that DC using that font. The context is that i want to draw a diagram with axis labels and axis titles using the same font but with different properties like normal or bold and different orientations.

However to stay minimalistic, let's say i want to draw text horizontally in normal and bold as well as vertically in normal and bold. This would make up 4 different styles.

I came up with essentially a code like this:

int size_in_pt = 12;
const TCHAR *fontname = _T("Tahoma");
CFont myfont;
CClientDC dc(this);
CString textToPrint(_T("text1234"));
CRect textRect;

myFont.CreateFont(size_in_pt, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fontname);    
dc.SelectObject(&myFont);
dc.DrawText(textToPrint, textRect, DT_LEFT);

textRect.MoveToX(100);
myFont.CreateFont(size_in_pt, 0, 0, -90, 0, 0, 0, 0, 0, 0, 0, 0, 0, fontname);    
dc.SelectObject(&myFont);
dc.DrawText(textToPrint, textRect, DT_LEFT);

textRect.MoveToY(100);
myFont.CreateFont(size_in_pt, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, fontname);    
dc.SelectObject(&myFont);
dc.DrawText(textToPrint, textRect, DT_LEFT);

textRect.MoveToX(0);
myFont.CreateFont(size_in_pt, 0, 0, -90, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, fontname);    
dc.SelectObject(&myFont);
dc.DrawText(textToPrint, textRect, DT_LEFT);

You can see that it is quite annoying that i have to CreateFont and SelectObject several times. I don't like this. I would like to create the font one time and select it into the DC one time and then only change the font properties like bold and orientation between each DrawText.

Do you have experience with such a case and maybe have an idea how to make to code more elegant and less repetitive?

  • 2
    You may not like it, but this is how Win32/GDI is designed. There's no function like SetFontProperties(). All you can do, to make your code nicer, is encapsulate this in some class, or simply write some function - there's some repetitive code pattern here after all. – Constantine Georgiou May 15 '20 at 11:58
  • I'm currently trying to deal with it somehow, e.g by encapsulation. However, i'm still hoping that this is not the final answer and someone comes up with some mystical trickery which makes that more convenient. Anyway, thank you! – Wör Du Schnaffzig May 15 '20 at 12:09
  • 1
    What you could do instead is develop a markup language that sort of does what you want, and then write a parser to your grammar that does all this work behind the scenes, pushing CFonts onto a stack as you change the font "properties", then popping them off at the end of the nested font tags. The "pushing" and "popping" would do what you want, but behind the scenes it is doing all the SelectObject work. Old HTML maybe? – franji1 May 15 '20 at 13:42
  • 2
    This is the final answer. You cannot change a font once it has been created. Instead of focusing on improving an aspect of your code, that cannot be improved, you should consider improving the correctness. You must restore a DC to its initial state before releasing control over it. Your code does not. Likewise, calling `CreateFont` consecutively on the same `CFont` instance puts a fair amount of pressure on MFC's GDI object garbage collector. It's a lot easier to understand GDI resource handling when writing this code in C first. – IInspectable May 15 '20 at 14:14
  • OK, i'll accept this. I like the idea with the stack very much although a parser would probably be too much. Maybe a factory method will do which outputs `CFont` objects with a certain style from a initial font definition (e.g. name and size). Thank you for hinting me on the resource issues. I will take that seriously. However, please be understanding that i could not show the whole picture of that diagram drawing and the mentioned CFont wrapper class, which also includes a method to select the font into a given DC, saves the prev. GDIObj and at the end restores the stored object. – Wör Du Schnaffzig May 15 '20 at 15:01
  • 2
    The magic ingredients to that are [GetObject](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getobject) and [CreateFontIndirect](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfontindirectw). – IInspectable May 15 '20 at 22:25
  • You can use a `LOGFONT` structure filling it for the first case and use it. Next every time you need to do a change, set the small bits you need and use it as you please. – sergiol May 29 '20 at 22:03

0 Answers0