In our previous issues, we’ve
covered quite a bit of API programming concepts, from basics like window classes,
instances, handles, etc, to creating our editor with basic functionality and menus. This
month, we take a break from the dull world of text, and see how to handle graphics (or
painting, as it is called) in Windows.
In the good old days of DOS, one would simply use the mem command to poke values in the
screen buffer. This was the fastest way of displaying images, and most serious graphics
programmers actually created their own libraries of high-speed graphics. All these methods
would basically rely on direct hardware access, which was okay, since there was only one
application accessing the entire computer at any point in time.
align="right" hspace="5" vspace="5">However, things got a little different, in Windows at
any time there may be any number of applications that may want to display information.
Information from each window has to be preserved, which would not happen in case of direct
hardware calls (they would overwrite the display under them). For this reason, all output
to the screen is handled by Windows and direct hardware access is usually not allowed.
Another reason for this is the wide number of hardware that Windows runs on. directly
handling hardware would mean writing a separate program for each different device.
However, if Windows were to handle it, it would route the actual functionality via a
display driver, which would be installed for specific display, and know how to work things
out.
In DOS, the entire screen area was available for use by the application. In Windows,
applications use windows as their primary output device instead of the screen. To identify
the displayable surface of each different window, Windows issues a device context (dc) to
each window. This dc is unique for every window, and applications can write to any window,
if they know the dc for that particular window. This way, any application can draw in any
window, without the fear of any information being lost.
When we talk about painting or drawing on a window, a message we discussed a long time
back should be recalled–the WM_PAINT message. This is the message Windows uses to
tell a window that it needs to be repainted. This would probably result in the window
repainting its contents. For example, if an overlapped window is suddenly brought to
front, it receives a WM_PAINT message, so that it can repaint itself. WM_PAINT is also
sent when a move or resize of the window happens. The actual window (the window border,
caption, etc), is repainted by a different message (WM_NCPAINT). In fact, one can write a
custom handler for this message and give the window a completely different look.
To draw in a window, the application must first retrieve the dc of that window. This is
done using the GetDC function. This retrieves a handle of a display device context for the
client area of the specified window. The display device context can be used in subsequent
GDI functions to draw in the client area of the window.
HDC GetDC(
HWND hWnd // handle of window
);
Here, hWnd identifies the window whose device context is to be retrieved.
Note that this function returns the HDC–the handle of the dc. This might
sound familiar, as windows also has handles (hwnd). Almost everything in windows is
referenced using handles, so one might as well get used to this method.
Once you’ve the dc, you can use the numerous powerful graphics operations that
Windows provides for painting. For example, to draw a rectangle on the dc, simply use the
following function:
rectangle(dc, x1, y1, x2, y2);
Here dc is the handle of the display context on which the rectangle is to be drawn.
After that are the coordinates of the top-left and bottom-right corners of the rectangle.
Note that these coordinates are relative to the top-left corner of the window in which
this is being drawn. The window’s top-left corner is (0,0), with the x
increasing from left to right, and the y increasing from top to bottom.
If you try drawing this rectangle, you’ll notice that Windows uses a specific
color to draw the rectangle. Also, it is filled with a specific color and pattern (could
be solid). These color and style values are actually derived from the window class (if you
remember we had filled in these values in the TWndClass structure before using the
RegisterClass function. The color and style of the rectangle is defined by the pen
of the dc, and the color and style of the "fill" is defined by the brush
of the dc. By changing these two before any drawing operation, all subsequent drawing
operations will be effected.
Next month, we’ll see how we actually handle the painting, pens, brushes etc, and
how we create graphics objects. We’ll also create a small "Paintbrush" like
program, but until then, happy coding!