• 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
  code.kliu.org said:
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
  Patrick333 said:
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
  code.kliu.org said:
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
  hdood said:
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.
  • Posts

    • I will confirm the Vista hate was ridiculous. They had a point before SP1 and too many didn't use newer components at launch, misleading some to believe it was bad. It really wasn't (after SP1.) The jump from 98/ME to XP didn't get a bad reaction at all from what I remember. 8 was awful. 10 for the most part ran pretty well but people disliked the telemetry and standard MS shenanigans, but 11 is definitely worse in some ways.
    • What I can confirm to not be exaggerations or misinformation is the slowness of the standard right click menus and the Task Manager in Windows 11, even on brand spanking new bare installs.
    • Linux 6.16-rc2: Smaller than usual, but with notable network and bcachefs tweaks by Paul Hill Linus Torvalds, the creator of the Linux kernel, has just released the second release candidate of Linux 6.16. Following the release of Linux 6.15, developers submitted their new features to be merged with Linux 6.16. These release candidates are focused on polishing the kernel before release, following the merging of new features. In his weekly mailing list post, Torvalds noticed that things were pretty quiet this week and that this could be due to developers taking a summer vacation or just taking a break following a large merge window a few weeks ago. This isn’t uncommon at this point in the cycle and Torvalds expects more activity next week. Networking and bcachefs dominate changes The second release candidate, despite being small, still brings some notable changes, namely network drivers, Bluetooth drivers, and bcachefs, a copy-on-write filesystem for Linux. The improvements to network drivers have a direct impact on end users, it means that newer networking hardware works out of the box when you install Linux and existing problematic drivers get fixed. There were also improvements made to the Rust infrastructure and core networking changes. Implementing Rust in the kernel is good for users as it has memory safety built in, leaving hackers less to attack in Linux systems. Rust has received backlash by some opinionated Linux developers who don’t want to learn a new language, but it doesn’t look like it’s going anywhere. Under the hood: specific fixes This week, a diverse set of developers have contributed fixes to the kernel that improve kernel stability, Bluetooth connectivity, file sharing over SMB, and virtualization performance. Some specific changes this week include: Fixes for CPU burning, firmware stats, and use-after-free (UAF) issues with the ath11k and ath12k Wi-Fi drivers. Various fixes for UAF, NULL pointer differences and advertising issues in Bluetooth drivers. Improvements to Server Message Block (SMB) related to directory cache reuse and a fix for performance regression with deferred closes. In KVM (Kernel-based Virtual Machine), there are fixes for SEV-SNP support, memory pre-faulting, and ARM64 selftests. The SMB fixes are notable because it's an important protocol in networked Windows environments. It helps with file sharing, printer sharing, and Active Directory integration. By improving Linux’s support for this protocol, readers using SMB in Linux to talk to Windows machines will have a smoother experience. Ongoing development Linux 6.16 is due to get seven or eight release candidates over the cycle so there are now five or six weeks until the stable version arrives. Even when it is out, most people’s first use of this kernel will be when distributions decide to ship it, as they can be tricky to install manually. Stay tuned each week as we bring you all the new changes which each new release candidate.
    • Just checked my B650 Motherboard again, nothing there as yet, Guess 800 series getting it first, which i can understand as that's newer series, and chipset. I'll check again in a few days or a week depending on how busy i am
  • Recent Achievements

    • Explorer
      Legend20 went up a rank
      Explorer
    • One Month Later
      jezzzy earned a badge
      One Month Later
    • First Post
      CSpera earned a badge
      First Post
    • One Month Later
      MIR JOHNNY BLAZE earned a badge
      One Month Later
    • Apprentice
      Wireless wookie went up a rank
      Apprentice
  • Popular Contributors

    1. 1
      +primortal
      624
    2. 2
      ATLien_0
      275
    3. 3
      +FloatingFatMan
      178
    4. 4
      Michael Scrip
      152
    5. 5
      Steven P.
      115
  • Tell a friend

    Love Neowin? Tell a friend!