• 0

[C++, Win32] Window/Control font & background colour


Question

I'm having problems here, C++ Win32 GUI programming is hard!

Problem #1: When i created the project in visual studio, it gave me some code that produced the main window. The code specifies the background colour for the window class as COLOR_WINDOW+1. However, here on Windows 7, that's white! I'd really like it to be light grey as per the norm. I can get this with COLOR_WINDOW without the '+1'. But i'm worried about the effect of this across other versions of windows and custom themes. Is this the recommended solution, or should I do it a different way?

Problem #2: More importantly, I'm having trouble with fonts! I've created a new window (an actual window, not a dialog), and created a button on it. The font used for the button is a really old system font (bold, black, and blocky). How do I get the window and all of it's controls to take on the default system font (Segoe UI for win7)? I've spent hours on this and haven't come up with an answer yet :(

SYSTEM_FONT and DEFAULT_GUI_FONT are apparently obsolete. I've heard about a SystemParametersInfo() function, NONCLIENTMETRICS sturctures and LOGFONTs. Am I going down the right path with that? How does this help me? Do i want lfMessageFont ("information about the font used in message boxes")????

I'm doing everything the hard way btw. Plain old C++, Win32, no MFC, no "forms", no dialog boxes designed in a resource file, and it's my first gui app using C++.

Please help...

12 answers to this question

Recommended Posts

  • 0

For #1: You "need" the "+1" so if you want to use COLOR_BTNFACE you need to have "COLOR_BTNFACE + 1"

For #2: I'd go along what you were saying with the lfMessageFont, simple call to CreateFontIndirect() will give you the HFONT needed for the WM_SETFONT message.

  • 0

Unfortunately, this is the way of c-based GUI programming. It's a remarkable pain. Pretty soon you'll realize why even commercial software devs are starting to switch to .NET to program the user interface and calling native code for operations that benefit from it.

  • 0

ok, almost there...

problem #1: I've used "COLOR_BTNFACE+1" as suggested.

problem #2:

first, the code, just to help others...

----------------

i'm using the following code to get the font:

HFONT hGlobalFont = NULL;
void GetWndFont()
{
	NONCLIENTMETRICS info;
	info.cbSize = sizeof(info);
	::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
	hGlobalFont = CreateFontIndirect(&info.lfMessageFont);
}

and then to set the font, for a single control:

SendMessage(hwnd, WM_SETFONT, (WPARAM)hGlobalFont, MAKELPARAM(FALSE, 0));

for all child windows:

EnumChildWindows(parentHwnd, setWndFont, NULL);

//callback function to be used by EnumChildWindow()
BOOL CALLBACK setWndFont(HWND itemHwnd, LPARAM lParam)
{
	SendMessage(itemHwnd, WM_SETFONT, (WPARAM)hGlobalFontt, MAKELPARAM(FALSE, 0));
	return true;
}

----------------

With the above, I've got the correct font applied to all of the window controls. I also sent a message to the window itself, though i'm not certain it had any effect.

There are a couple of little quirks with my window I'd like to solve though:

1) Size discrepancies.

Before attempting to make the window in C++, I designed it as a VB.Net form. I took the unit positions and sizes from the properties of everything in VB and used them in my CreateWindow() statements in C++. Comparing the two windows, they're not quite the same though!...

- The width and height of the C++ window are slightly larger. There's 3mm difference on my screen, and leaves a gap between the controls and the right and bottom borders (all controls seem to line up correctly comparing the two windows). I set the font on the actual window in the VB.Net form to the same as for the controls below. Changing the size of the VB.Net form's font does not increase the size of the form until I get to 8.63pt, and then it is much larger than the C++ form, about 1 inch for height and width. (My screen is 21.5" 1680x1050).

- The original font in the VB form was "Microsoft Sans Serif, 8.25pt". I changed this to "Segoe UI, 8.25pt". The font size is too small though compared to the C++ window. If I increase it to "Segoe UI, 8.26pt" the font to me looks like it matches the C++ form, although it is very hard to tell. 8.26-9pt all seem the same as far as i can tell, the size of the text increases again at 9.1pt. However, even at just 8.26pt the text on a couple of the buttons does not fit and spills over into multiple lines, whereas the same text in what looks to be the same sized font in the C++ buttons, is fine...

Can anyone shed any light on this, and tell me how I can get the design to match the result?

I know I can just alter the unit sizes i'm using, to fix the fundamental issue, but I'd really prefer to tackle the cause!...

2) In *some* of the the corners of *some* of the text boxes, there's a little dark grey dot. Zooming in, they're not all the same shade. Switching window/control focus can change how many of them there are... Maybe it's a Windows 7 bug... But yet the VB.Net form doesn't do this...

Screenshot showing the problems (C++ on the left, VB.Net on the right):

post-51082-1251656129_thumb.png

Edit: Thought. The size of text in child windows seems to be effected by the font of the parent window, when playing around with VB.Net. Could it be that all of the size problems stem from the WM_SETFONT message having no effect what-so-ever on the C++ parent window, and therefore it's basing the size of everything based on aspects of that old system font it was previously using? If so, how do I fix this?

Edited by theblazingangel
  • 0

Win32 GUI programming shouldn't be this difficult because you shouldn't be doing everything using the raw C APIs (BTW, the API is in C, not C++).

There are several ways to do Win32 GUIs:

1) Raw calls to the raw C APIs such as CreateWindow, etc. This is complicated, tedious, and relatively speaking, it's rarely used. It's used only in situations where you need such low-level control over the UI or in situations where it's easier to do it this way.

2) Use the dialog manager. Most of the UI in the Windows operating system itself uses the dialog manager. The dialog manager has been around for a long time (I think been around since Windows 2?), uses a simple C API, and support for it is built into the OS. In fact, Microsoft's UI layout guidelines were written specifically for windows created with the dialog editor (using DPI-independent dialog units) (to adhere to these guidelines using any other method of GUI programming will require that you do conversions).

3) Use MFC. This is a set of C++ wrapper classes for the low-level C APIs. The problem with MFC is that it introduces MFC dependencies. MSFT doesn't use MFC very much.

4) Use a third-party widget layer like wxWindows. Common with open-source projects, it does introduce dependencies, but nothing major.

5) Use various .NET stuff. The problem with .NET is that, well, it's .NET, and you get all the baggage and truckload of dependencies that come with that.

Using the raw API is, as I said, relatively rare, and is usually used on windows with very limited complexity. For example, if you are writing a file manager, you would create the main window using approach #1, which would consist of just a menu bar, a toolbar, a status bar, and a list view--just four UI elements that require very little in the way of positioning or layout. And then all of your other UI--your options dialog, your file information dialog, etc.--would be done using the dialog editor. In fact, if you look at Windows itself, this is how much of the OS is done: low-level CreateWindow is used only for the "main" window with generally limited complexity, and everything else is done with the dialog editor. And if your app just consists of a dialog-like window, then your entire program's UI should be done with the dialog editor (or you could manually write the dialog resource without the editor).

So yes, what you are doing is hard. And complicated. And that's why you're not supposed to do it that way, and that's why even Windows itself doesn't do it that way. I can understand wanting to avoid MFC or .NET (because I, too, avoid them), but the dialog system is really another matter. The dialog manager is built into the OS itself, as a part of user32.dll. And just like CreateWindow and the other low-level stuff, you work with the dialog manager using a C API.

Edited by code.kliu.org
  • 0

A few extra notes:

1) Don't compare a .NET form with a native form. Many .NET controls are not rendered natively, but instead, through a series of manual calls to uxtheme or are self-drawn in a way to emulate native controls. You can tell the difference by noting the lack of a hover fade animation on buttons in themed mode, or in classic mode, the (erroneous and incorrect) failure of .NET controls to respect the 3D light color setting. I don't know what other rendering differences there are, since I rarely touch .NET, but it should be noted that they are not directly comparable. You should be comparing what you get with what you create using the dialog editor, which is native.

2) Pay close attention to the documentation regarding LOGFONT. Namely, how font sizes are natively represented and handled and how that differs from the point size that you specify; this should explain some of the font-size-related questions that you had.

3) I'm not sure about the gray dots. Do you see them with a dialog-editor window?

Edited by code.kliu.org
  • 0

This is mostly just a learning exercise, which is why I'm doing it this way. I'd certainly consider other options for future projects.

I'm not using MFC partly to learn how to do it without first, but also because I'm using the express edition of VC which doesn't have MFC!

I'm avoiding dialogs, again partly to learn how to do it without, but also because the express edition of VC doesn't have the resource file editor that the full version has, and I'm affraid of forgetting to backup the .rc file and VC erasing all my hard work.

In regard to the problems in my last post. I've fixed the grey dot problem! The controls were within a groupbox and I had set the groupbox as their parent window. I just discovered today that groupboxes don't pass messages from controls up to their parent window. I'm now using a RECT for easy positioning of controls, and no longer using the groupboxes themselves as parent windows to the controls they contain. This magically solved the mysterious grey dot problem!

As for the size problem, I've taken onboard what you said about .Net forms, and I'll forget trying to precisely match the C++ form to it.

thanks.

  • 0
Win32 GUI programming shouldn't be this difficult because you shouldn't be doing everything using the raw C APIs (BTW, the API is in C, not C++).

1) Raw calls to the raw C APIs such as CreateWindow, etc. This is complicated, tedious, and relatively speaking, it's rarely used.

2) Use the dialog manager. Most of the UI in the Windows operating system itself uses the dialog manager.

It's total BS.

CreateWindow() is used everywhere inside Windows source code !!! (that apparently you never studied..)

You even don't know what is "Dialog manager" : it's a kernel part which manages Dialog Boxes (off topic !)

I make GUI with CreateWindow() and all native, common and avanced controls for nearly 20 years. It's just unbeatable and the best way to manage and understand everything.

  • 0
CreateWindow() is used everywhere inside Windows source code !!!

Define "everywhere". Your claims are, of course, patently false by the strict definition of "everywhere". But even with a loose definition of "in most situations", you are still wrong. Just poke around Explorer (shell32.dll and explorer.exe) or mspaint.exe. Tell me, how many dialog resources do you see? And now, tell me, how many calls to CreateWindowEx do you count? My disassembler counts 6 calls to CWEx in shell32.dll (3 in explorer.exe) in 5.1.2600. And I see a list of dialog resources so long that they overflow my screen. So, shall we discuss this definition of "everywhere"...?

Yes, I know what the dialog manager is, and yes, it is managing dialog boxes. Which is what we're talking about: UIs that take the form and style of dialog boxes (i.e., most of the UI in Windows, in terms of sheer quantity, and, more to the point, what the OP was trying to implement) should be implemented using the various dlg functions. Of course, as you can attest, this is not a requirement, and if someone feels so inclined to manually create every button, every text box, etc., they can. But it's also not a requirement that people use C; you are certainly free to write your program using x86 assembly if you wanted, but that doesn't mean that it's a particularly good idea.

And no, strictly speaking, it's not a part of the kernel. It's a part of the user subsystem. And not only that, it's implemented using the lower level calls such as CWEx, and it is implemented as more or less a wrapper around these various calls (and there has been much discussion elsewhere about just how the dialog "manager" works, how it is implemented, and how one might write their own dialog "manager" if they are not quite satisfied with what Windows has).

  • 0

Saying that dialogs are "most used" is a bit misleading. Programs tend to only have one main UI, but dozens of popup dialogs. If you look at Explorer (the desktop and file browser), what you are seeing is not a dialog. The same holds true for most programs (although you will occasionally find people having child dialogs in a window).

And for the pedants, Windows today technically only has one subsystem, Win32. Windowing (user) is part of that, although most of the functionality runs in a kernel-mode driver rather than in the subsystem process (which doesn't do much these days) itself. Completely irrelevant to anything though.

  • 0
A few extra notes:

1) Don't compare a .NET form with a native form. Many .NET controls are not rendered natively, but instead, through a series of manual calls to uxtheme or are self-drawn in a way to emulate native controls.

Interesting. I know it isn't really related to this thread but I always wondered why there were sometimes inconsistencies. Thanks for the info.

  • 0
Saying that dialogs are "most used" is a bit misleading. Programs tend to only have one main UI, but dozens of popup dialogs. If you look at Explorer (the desktop and file browser), what you are seeing is not a dialog. The same holds true for most programs (although you will occasionally find people having child dialogs in a window).

Yes, that is true, which is why I did specify in the first post that the "main" UI is usually manually created (because, except for tools and utilities, the "main" UI of an application usually does not take the form of a dialog), and this is also why I qualified my later post with "in terms of sheer quantity".

And yea, subsystem probably wasn't the best word. Component, perhaps? The distinction that I was trying to make was that it's code that exists in a layer above what one normally associates with the "kernel" (with respect to the hierarchy of dependencies).

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.