csammisrun

A rare situation

Chapter 8

without comments

Making JotStuffDownPad look purdy

We now have a perfectly working application…whoo!

JotStuffDownPad 1.0

However, something that isn’t usually a big concern with console programs is about to rear its ugly head: JotStuffDownPad is UGLY. The fonts are blocky (if you’re using Windows NT/2000/XP, at least), the default icon is bland, and resizing the window looks horrific:

Ugh, not cool

Win32 GUI programming requires its programers to be a bit artistic, admittedly, but everyone can agree that a program that looks good is more likely to do well with users than an uglified counterpart that performs the exact same function. To that end, and to finish up JotStuffDownPad, this chapter will introduce you to working with fonts, installing a custom icon and working with resource files, and processing yet another window message to make controls move alongside their parent window. And, wheeeeee!

Setting fonts

I’m going to be perfectly candid; those who have followed my tutorial to this point deserve no less. It’s my firm belief that working with fonts is one of the Black Arts of programming. It’s not a very easy task, and to the extent that I know how to do it, it requires a lot of patience while you make your font look right.

Okay, my rant’s over, now for some useful information. Using Win32 GUI programming, it’s usually not as simple as saying “I want to set this font to Courier New”. However, for some basic fonts, it is very nearly that simple. The “simple” method is what we’re going to cover here; hopefully, the more difficult methods of building fonts from scratch will be covered later in the tutorial.

Let’s look at some code we wrote back in chapter four, specifically in . Take a look at these lines:

// hIcon: a handle to the icon to display in the Alt-Tab window
//        and on the desktop (and large icon view in Explorer).
//        Here we load a default icon supplied by Windows.
wcx.hIcon = LoadIcon(NULL,IDI_APPLICATION);

Windows handily supplied us with a default icon because we didn’t create one of our own. Windows also has a supply of default items that are used to draw objects (windows and controls) with different patterns, colors, and fonts. These default drawing tools are called stock objects and are part of the Windows GDI, or Graphics Device Interface (in contrast, the object returned by is contained in a resource file used by Windows, more on that later).

To load a stock object and use it ourselves, we call , which returns a handle to the requested object. MSDN tells us that there are 19 possible stock objects that can be retrieved, but the ones we’re interested in are the seven font objects:

  • ANSI_FIXED_FONT
  • ANSI_VAR_FONT
  • DEVICE_DEFAULT_FONT — this is available on Windows NT/2000/XP only
  • DEFAULT_GUI_FONT — this is the font used to draw menus
  • OEM_FIXED_FONT
  • SYSTEM_FONT — this is the font that is used by default; MS Sans Serif on Windows 95/98/ME, and Tahoma on Windows NT/2000/XP
  • SYSTEM_FIXED_FONT — not used; this is provided for compatibility with versions of Windows less than 3.0

Now we pick which font we want to use. Largely, this is up to you as the designer of the program. Feel free to use different stock fonts, and experiment to see what you like. For this tutorial, I’m going to stick with the mainstream and put the default GUI font on each control. This will make JotStuffDownPad’s controls appear like most other controls in most other applications.

We’re going to modify to apply the font changes after all the controls are successfully created, and just before the statement. To do this, we declare an handle to hold the return value from . We then go through each control and send it the message, which takes the handle to the new font in the wParam argument and in the lParam argument (this tells Windows to redraw the control with the new font). Here we go…

bool BuildControls(HWND parent)
{
	...
	// Get a handle to the stock font object
	HGDIOBJ hObj = GetStockObject(DEFAULT_GUI_FONT);
	// Set the font on each control
	SendMessage(editField, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(newButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(deleteButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(saveButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(exitButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(comboNotes, WM_SETFONT,(WPARAM)hObj, true);
	return true;
}

Press F5, and see the fruits of that small labor…

JotStuffDownPad with DEFAULT_GUI_FONT

Looks a lot better than the blocky , no? If you’re using Windows 95/98/ME, you may not have noticed a difference; and may resolve to the same thing (MS Sans Serif) on those platforms. However, since the screenshots were taken under Windows XP, there is a lot of difference to be noticed!

Just for variety, let’s add a new wrinkle into our text editor. Often, when working with little text notes, it helps to be using a fixed-width font, such as Courier New. gives us a variable-width font, in which different characters have different widths and text on multiple lines is spaced differently. Arial, Times New Roman, Helvetica, and MS Sans Serif are all examples of fixed-width fonts. In order to give the text field a more “professional” look, we can give it a fixed-width font using :

bool BuildControls(HWND parent)
{
	...
	// Get a handle to the stock font object
	HGDIOBJ hObj = GetStockObject(DEFAULT_GUI_FONT);
	// Set the font on the buttons and combo box
	SendMessage(newButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(deleteButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(saveButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(exitButton, WM_SETFONT,(WPARAM)hObj, true);
	SendMessage(comboNotes, WM_SETFONT,(WPARAM)hObj, true);
	// Get a handle to a fixed-width font
	hObj = GetStockObject(ANSI_FIXED_FONT);
	// Set the font for the edit field
	SendMessage(editField, WM_SETFONT,(WPARAM)hObj, true);
	return true;
}

And that results in this, a font job well done!

Fixed-width fonts

Doing the “Dance of the Resizing Window”

As I’m sure you’ve noticed if you’ve played with resizing or maximizing JotStuffDownPad, strange stuff starts to happen when the window is resized. More to the point, nothing happens; the controls don’t stay with the edges of the window, and thus things start to look bizarre. This is fixable in one of two ways: Change the window border so that our application can’t be resized, or force the controls to resize themselves with the window. Both ways are valid; in fact, I’ll be creating controls that resize for the first time while writing this tutorial…I usually take the easy way out and forbide users to resize the window. This is perfectly reasonable, but since a tutorial is supposed to be a learning experience, we’re going to resize us some controls! We are actually only going to resize the edit control, for reasons that will probably become clear when it’s done.

For this to happen, we need to know when the window gets resized. By now we know enough to run to MSDN and look for the message or messages that get sent to the window when the window changes size. After some looking, we find two relevant messages: and . At first glance, seemed more reasonable to use. This message is sent whenever the window changes one pixel’s worth of size, and yes, that means that the window procedure is flooded with messages while it’s being resized. This is actually desirable though, because it will allow the edit control to resize smoothly, as the user drags the window border around.

However, as I said before, tutorials are learning processes for everyone. When I implemented control resizing based on , I learned that this messages is not sent when the window is maximized, only when the user resizes the window by dragging the window borders. Because of this, maximizing the window leaves JotStuffDownPad with a ridiculously undersized edit control. So I then started to implement control resizing with . MSDN tells us that the height and width of the window after it is resized (which is when the message is sent) are stored in the high- and low-order words of lParam, respectively. However, and this is important:

The width and height passed in through lParam do not include the title bar or the window borders!

This is a perpetual concern when dealing with window size; various methods of getting the size of a window return different sorts of values, all of which are correct in different ways. The parameters that passes in describe the dimensions of the drawing rectangle of the window; that is, the valid area on which controls and other items can be placed. This can be useful, but it’s not what we want here. We originally sized the edit control based on the full height and width of the parent window, so that’s what we must get now.

Getting the full size of the window involves a structure that we haven’t used before: a . A is simply a C-style with four members that describe the on-screen position of a rectangle. The coordinate system used by Windows gives (0,0) to be the upper-left hand corner of the desktop. The members of a are:

  • left - the x coordinate of the upper-right corner of the rectangle
  • top - the y coordinate of the upper-left corner of the rectangle
  • right - the x coordinate of the lower-right corner of the rectangle
  • bottom - the y coordinate of the lower-right corner of the rectangle

A little cleverness on the part of the programmer will reveal that we can derive the height and width of the rectangle as well:

  • height = bottom - top
  • width = right - left

We can get a that describes a given window by using the function, which takes an for the requested window and a to store the window’s position in. To make it easy on ourselves (and to make the compiler not complain about “possibly uninitialized variables”), we declare the variables we need at the top of the window procedure. We can then give values to the variables each time that is received:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	// Variables needed to process WM_SIZE
	RECT r;
	int currentWidth,currentHeight;

	switch(uMsg)
	{
	...
	case WM_SIZE:
		// Get the RECT for our window
		GetWindowRect(hwnd,&r);
		// Get the current height and width
		currentWidth = r.right - r.left;
		currentHeight = r.bottom - r.top;
		return 0;
	...
	}
	...
}

Now, this is where “thinking ahead” really helps. Do you remember back in chapter five when we were creating controls, we saved their heights, widths, and spacing in local variables? As useless as it might have seemed at the time, it was in preparation for a scenario like this. Since we already know the distance that we want between the edit control and the window, we can simply make that variable global and use it to quickly resize the control in the window procedure. Recall this code from (comments were removed for the sake of the size of this HTML file. This is from just before the call that created the edit control):

x = 5; y = y + butH + 10;
int editH = 400 - 30 - y, editW = 500 - 10 - 5;

When all is said and done, we’ve left the spacing at 30 pixels from the bottom and 15 pixels from the right side. Add two new statements and one variable to the global section of JotStuffDownPad.cpp, underneath the declarations:

#define SPACE_BOTTOM 30
#define SPACE_RIGHT 15
int editTop;

Now, change the aforementioned code in to use the new definitions and save the top of the edit control in the new variable. This is mostly for future flexibility; if we want to change the spacing at any point, we don’t want to have to dig through code when it’s already defined globally.

editH = 400 - SPACE_BOTTOM - y; editW = 500 - SPACE_RIGHT;
editTop = y;  // Save the top of the edit control

We need only one more piece of ammunition before we can finish coding the handler for the message, and that is a method to resize the edit control. We find this ammunition in the form of the function. is a rather bloated function; it can put a window on top (if another window is hiding it), put a window on the bottom (”underneath” all other open windows), move a window, and resize a window. All the parameters for all of these abilities must be passed to it, but the final argument for allows the programmer to set flags that tell the function to ignore all, some, or none of the values. A discussion of this function is given in much more detail in MSDN; for the purposes of this tutorial, we’ll only be using it to resize windows and controls.

For the record: the order in which windows are displayed on top or underneath each other is called the Z order. A window that is on top of all other windows is at the top of the Z order, and a window that is hidden by any other window being displayed is on the bottom of the Z order.

Now that we’re armed to the teeth with resizing knowledge, we can add in this code to the handler:

case WM_SIZE:
	// Get the RECT for our window
	GetWindowRect(hwnd,&r);
	// Get the current height and width
	currentHeight = r.bottom - r.top;
	currentWidth = r.right - r.left;
	// Resize the edit control, but tell SetWindowPos to ignore
	// the parameters that move the window and reposition it in the
	// Z order
	SetWindowPos(editField,NULL,0,0,currentWidth - SPACE_RIGHT,
		     currentHeight - SPACE_BOTTOM - editTop,
		     SWP_NOMOVE | SWP_NOZORDER);
	return 0;

Press F5 to test. And joy, it works! The edit control now resizes smoothly with the window, while remaining in one position relative to the other controls. Looks pretty sweet, doesn’t it? Well, it can look sweeter!

Introducing the resource file

Earlier in this chapter, while discussing stock objects, I mentioned that Windows retrieved the default icon that JotStuffDownPad is currently using from a resource file and that I would talk more on that subject later. The time has come!

Win32 GUI applications can have what are known as resource files. These “files” are compiled into the application at build time, and can contain all manner of interesting objects. Resource files are responsible for storing custom icons and mouse cursors, menus, bitmaps (images), dialogs (pre-built windows and controls), string tables, and other kinds of binary data such as WAV files.

As with most things, there are pros and cons to using a resource file. The big con to resource files is that using a resource file increases the application’s size and memory “footprint” (the amount of memory the application uses when loaded). To counteract this, a programmer might try keeping custom data like images in seperate files, and loading those files only when needed. This does indeed cut down on the memory footprint and application size, because the files are not stored within it. However, the downsides of this method tend to outweigh the benefits: Loading the files takes time because disk I/O is much slower than memory access, and distributing your application becomes something of a nightmare; more files to be packaged means more files that can get corrupted, removed, or changed by the user.

The pros of resource files greatly outweigh the cons. As I just said, accessing a resource from a location in memory is much faster than accessing a resource on a disk. Keeping all your resources compiled into the application also decreases the chances of having your files tampered with; if an application that is to be used in an office is supposed to load a WAV file and play it, the user would probably rather hear the quiet chime you intended than a loud obscenity that a prankster coworker may have put in the chime’s place (I know nothing about this). Lastly, there are simply some things that have to be done in resource files, and not with outside files. Dialogs and menus, for example, have to be loaded from a resource file because no mechanism exists to load them from a regular file.

Hopefully you’re at least partially convinced that resource files are Good Things. Eventually this tutorial will touch on using menus and dialogs, at the very least, but for now we’re going to focus on storing icons within JotStuffDownPad’s resource file.

Adding a personal touch with icons

There are two ways to create a custom icon for an application and put it in the resource file, and one involves drawing it yourself in Visual Studio’s icon editor. I never do this, and so I’ll show you how to take an already existing icon (or convert an existing image in some format like GIF, JPEG, or BMP to ICO format using a program like QTam Bitmap to Icon [shareware]), and then insert it into your application’s resource file. To handily demonstrate this, I’ve created an bitmap that we’ll convert using QTam Bitmap To Icon:

Download this file to your project directory, then launch QTam (or whatever program you want to use to convert the picture to an icon). If you’re doing this with your own bitmap, make sure that the bitmap is 32×32 pixels in size! QTam is fairly good about instructing you through the process, but I’ve posted a few words about using QTam to convert bitmaps just for kicks.

Once you’ve created the icon, save it to your project directory. Then in Visual Studio, go to the “Project” menu, then “Add To Project” and click “New…”. The following screen appears:

The Add To Project dialog

Select “Resource Script,” and give the resource script a name in the “File Name” field. This creates the resource script, and adds a new tab to the Workspace window. Now, to insert our icon, right-click on the resource file in the Workspace window and select “Import…”:

Importing the icon

Find your icon, and click “Open” to add it into the resource file. This opens the icon in Visual Studio’s icon editor. You can see in the Workspace window that your icon now has the beautiful name of .

Before your icon is fully added into the application, two more steps must be taken (really, two parts to one step). Resources within the resource file are identified by statements, and those are found in the file “resource.h”. As above, go to the “Project” menu, “Add To Project,” but this time click “Files…” and select “resource.h”, which is located in the project directory. Then open “StdAfx.h”, and add the following line:

#include "resource.h"

…and your icon’s added into the project! That wasn’t so bad, was it?

Now to tell JotStuffDownPad that we want to use the new icon. To do this, we have to change the code where we set the default icon the first time around. This is in our function. Instead of setting to , we set it to as such:


Editor’s note: I must apologize to everyone who has read through this tutorial and has seen it come to this abrupt end. Unfortunatly, this project has fallen by the wayside. Hopefully I’ll have time to pick it up again in May. Please check back!

Back to contents

Written by Chris

May 29th, 2007 at 6:39 pm

Posted in General

Leave a Reply