|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionMany developers are comfortable with obtaining a handle to a device context (DC) and painting to it. However there is probably alot of confusion in how all of the parts to windows painting are structured. Confusion in what the different DCs are good for, and how each of these DCs can be used effectively. This article will describe in detail, how the different parts of the WIN32 paint system are combined and how to use the common and device DCs in the paint system. The memory and metafile DCs will be ignored in this article. This tutorial will also explain how the SDK relates to each of the wrapper classes for MFC and WTL. With this knowledge, developers can then make wiser decisions on when you will create, cache, and use DCs in your Windows painting. The tutorials and code examples are written in WTL, however, the wrapper classes are very similar for both MFC and WTL. There is a beginner tutorial that precedes this article. The preceding artical covers basics of painting to a window with a DC. This article is entitled: Guide to WIN32 Paint for Beginners. Anatomy of a WindowA window is the fundamental object through which information is conveyed to a user in WIN32 operating systems. A window is a system resource that is managed by the operating system and can be accessed by the host application with a window handle (HWND). There are many pieces of information that describe a window. This section will describe the different characteristics that relate to paint. Physical CharacteristicsThe portion of a window where most of the information is displayed is called the client area. Most often this area is represented by a rectangle. The rectangle can be retrieved from the window with this function: ::GetClientRect(HWND hWnd, RECT *pRect); Often times, the client area will be surrounded by a region of the window called the non-client area. The non-client area encompasses the window borders, caption and the menus if any are present. A rectangle that represents the non-client area can be retrieved from the window with this function: ::GetWindowRect(HWND hWnd, RECT *pRect);This function differs from GetClientRect in the fact that the rectangle is
returned in screen coordinates, and the rectangle also encompasses the client area of the
window. Therefore, if an application simply wants to access the region that represents the
client area of the window, then this code must be performed:RECT rWindow; RECT rClient; HRGN hRgnWindow; HRGN hRgnClient; HRGN hNCRgn; //C: Get the window and client rectangles for the window. ::GetWindowRect(hWnd, &rWindow); ::GetClientRect(hWnd, &rClient); //C: Translate the Client rectangle into screen coordinates. POINT pt = {0,0}; ::MapWindowPoints(hWnd, NULL, &pt, 1); ::OffsetRect(&rClient, pt.x, pt.y); //C: Create regions from these two rectangles. hRgnWindow = ::CreateRectRgnIndirect(&rWindow); hRgnClient = ::CreateRectRgnIndirect(&rClient); hNCRgn = ::CreateRectRgn(0,0,0,0); //C: Subtract the client region from the window region. ::CombineRgn(hNCRgn, hWindowRgn, hClientRgn, RGN_DIFF); //C: Perform actions on the NC region. ... //C: Free region resources. ::DeleteObject(hRgnWindow); ::DeleteObject(hRgnClient); ::DeleteObject(hNCRgn); Here is a picture that illustrates the different regions of a window: Update RegionThe WIN32 kernel manages the state of a window. One of the most important elements of a window is its update region. The update region remembers all of the portions of the window that need to be redrawn. A region may need to be redrawn for a number of reasons:
At any point in time the application can query the current update region for a window with this code: //C: This code will get the entire update region. HRGN hUpdateRgn; hUpdateRgn = ::CreateRectRgn(0,0,0,0); ::GetUpdateRgn(hWnd, hUpdateRgn, FALSE); //C: This code will simply retrieve the bounding box of the update region. RECT rUpdateBox; ::GetUpdateRect(hWnd, &rUpdateBox, FALSE);The update region can be very important for applications that would like to clip their painting code to the update region in order to improve performance. The application can modify the update region manually, either by adding a new portion to the update region, in effect invalidating the region, or by subtracting away from the update region, or validating that region. Here is the set of functions that can be used to modify the update region. InvalidateRectThe InvalidateRect function adds a rectangle to the specified window's update region. BOOL InvalidateRect( HWND hWnd, // handle to window CONST RECT *lpRect, // rectangle coordinates BOOL bErase // erase state ); InvalidateRgnThe InvalidateRgn function invalidates the client area within the specified region by adding it to the current update region of a window. BOOL InvalidateRgn( HWND hWnd, // handle to window HRGN hRgn, // handle to region BOOL bErase // erase state ); ValidateRectThe ValidateRect function validates the client area within a rectangle by removing the rectangle from the update region of the specified window. BOOL ValidateRect( HWND hWnd, // handle to window CONST RECT *lpRect // validation rectangle coordinates ); ValidateRgnThe ValidateRgn function validates the client area within a region by removing the region from the current update region of the specified window. BOOL ValidateRgn( HWND hWnd, // handle to window HRGN hRgn // handle to region ); RedrawWindowThe RedrawWindow function updates the specified rectangle or region in a window's client area. This function will modify the update region. This function can also force a repaint of the window and its children based on the flags that are set. BOOL RedrawWindow( HWND hWnd, // handle to window CONST RECT *lprcUpdate, // update rectangle HRGN hrgnUpdate, // handle to update region UINT flags // array of redraw flags ); Here is a list of the flags that can be used with this function and a short description of what each flag does:
Class Styles that Affect the Update RegionThere are two class styles for a window that will affect the update region for
a window when the window is sized. These are The WM_PAINT / WM_NCPAINT MessagesA window is responsible to paint its own display. A window should paint its
display in response to a When the The WM_ERASEBKGND MessageThe The Device ContextsThere are four types of DCs. The fundamental purpose of each DC is to provide a basis for drawing on a device. The area that can be drawn is determined by the type of DC that is created. This section will describe the different types of DCs that are used in painting and how they are encapsulated by MFC and WTL. The first type of DC that will be described is the common DC. The common DC encapsulates two types of DCs, the window DC and the client DC. Then a second section will follow with Device DCs. These are DCs that represent any device on your machine, that supports some form of the Windows Graphics Device Interface (GDI). Two other types of DCs are ignored in this article, memory DCs, and metafile DCs. A DC is an operating system resource. Because of this, it is very important that DCs are released when they are no longer required. Do not cache DCs. Each type of DC has its own method to release that DC. It is important to use the proper function because these functions act like desctructors, and important shutdown operations occur in these functions for the particular type of DC. If an application performs a lengthy operation each time to initialize a DC, then a class or private DC can be created. That will be explained at the end of this section. Common DCsCommon DCs are created from a pool of DCs that is limited by the amount of memory on
the current system. Common DCs are futher classified as Client and Window DCs.
Client and Window DCs are avery similar. The only difference between the two is that
a client DC is restricted to the client area of the window, while the window DC gives the
application access to both the client and the non-client areas of the window. There are
two functions that allow access to a client DC ( Listed below is each of the functions that can be used to created a DC for a window. Any special characteristics about each function are described, as well as special uses. Paint DCA paint DC is represented in MFC and WTL by the HDC BeginPaint( HWND hwnd, // handle to window LPPAINTSTRUCT lpPaint // paint information );
Here is the layout of the struct PAINTSTRUCT { HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; BYTE rgbReserved[32]; };Here is a description of each of the fields:
The BOOL EndPaint( HWND hWnd, // handle to window CONST PAINTSTRUCT *lpPaint // paint data ); The only place that Client DCA DC that paints the client area, but is not a Paint DC is referred to a HDC GetDC( HWND hWnd // handle to window ); After painting with a common DC, the int ReleaseDC( HWND hWnd, // handle to window that the DC was created for. HDC hDC // handle to DC ); Window DCA Window DC allows for the entire window, including title bar, menus, and scroll bars, to be
painted. A window device context permits painting anywhere in a window, because the origin
of the device context is the upper-left corner of the window instead of the client area.
MFC and WTL represent this DC with the HDC GetWindowDC( HWND hWnd // handle to window ); As with GetDCEx
HDC GetDCEx( HWND hWnd, // handle to window HRGN hrgnClip, // handle to clipping region DWORD flags // creation options ); The
As stated earlier,
Class / Private DCsIt is important not to cache the common DCs in an application. How then can an application create a DC that does not have to be reinitialized each time it is called? This can be done with either a class or private DC. These two DCs can be retrieved in the same manner as the other common DCs and they do not need to be released. However it is good practice to release these DCs as the release functions have no effect, and memory leaks will be prevented if the DCs are ever converted back to common DCs. Class and private DCs are persistant, therefore the state of the DC will remain the same as it was in the previous call to that DC. This will allow a DC to be initialized once. This could save valuable time for applications that have lengthy DC initializations. Given below is a short description of both the class and private DC.
A class DC is created for use for a single window class. In order to create a class DC, the
window class must have the A private DC is created for one particular window. To create a private DC, the
Device DCsA device DC allows access to any device on the system that supports some portion of the WIN32 GDI. All types of devices can be accessed like the "DISPLAY" driver, secondary monitors, printers, plotters and any other cutting-edge device that supports GDI. There are two steps that are required to get a handle to a device DC. 1) Get the name of the
device. 2) Call Obtain Device NameMost simply, if the application would like a DC to the primary display device, then the
string "DISPLAY" can be used. However if a DC is to be created for secondary monitor then
In order to get the name of a printer device, the application should use CreateDCThe CreateDC function creates a DC for a device using the specified name. HDC CreateDC( LPCTSTR lpszDriver, // driver name LPCTSTR lpszDevice, // device name LPCTSTR lpszOutput, // not used; should be NULL CONST DEVMODE *lpInitData // optional printer data ); The lpInitData, or CreateICThe CreateIC function creates an information context for the specified device.
The information context provides a fast way to get information about the device
without creating a device context (DC). However, GDI drawing functions cannot accept
a handle to an information context. This function should be followed by a call
to HDC CreateIC( LPCTSTR lpszDriver, // driver name LPCTSTR lpszDevice, // device name LPCTSTR lpszOutput, // port or file name CONST DEVMODE *lpdvmInit // optional initialization data ); DemonstrationThe program that has been created to demonstrate the topics covered in this article
will visualize the update region for the user. Other information will also be displayed
in either the non-client area of the main window, or directly on one of the display
drivers. One other feature of the demo application is to turn off the handling
of the Because of the multi-monitor testing, this application requires WIN98, WIN200 or above.
This application is written in WTL, therefore the WTL header files will be required
to build the source project. The WTL wrapper classes ( Use if this application is very simple. Run the application, can force the main window to redraw itself. There are many ways to do this including:
Each time that a Data LogThe data log contains the important and usable values of the
Selecting No Log on the menu will hide the data bar. If Non-client is selected on the menu, then the data bar will be painted in the border area of the
window. This is done to illustrate how painting can be accomplished in the This program will enumerate up to two display devices on your machine, and add them to the view menu.
If you select one of these items, then the databar will be displayed in the upper-left hand corner of
the monitor that the display represents. The CS_HREDRAW / CS_VREDRAW stylesAs described earlier in the article, these styles affect the update region. If one of these styles is set, then when the window is resized the corresponding style may force the entire view to be redrawn rather than simply the new update region. Change this style, and watch the effect that is has on the update region. WM_ERASEBKGNDIf this option is set, then the application will process the WM_ERASEBKGND message, effectively clearing
the background during each Also notice the fErase field value in the data bar. When Show Window Contents While DraggingThis will toggle the setting in the display properties that forces the window to repaint while a window is begin dragged. Whether it is being resized, or another window is being dragged across the top of the window. The net effect of this option being set is that more paint messages will be generated, and the update regions will be smaller, but more frequent. This application should be viewed with this option on and off. Here is an example of the difference when resizing the window.  
Short comingsThere are two minor short coming in this demonstration application when the databar is painted on one of the display adapters. The application does not try to erase or restore the previous data when the data bar is removed. This could have been fixed by caching the region where the data bar is painted, and restoring that region when the data bar is removed. However that would require memory DCs, and this article ignored their explanation. When the data bar is displayed on one of the display adapters, but it is also painted onto a window from a different application, it may appear that the data bar has missed a region that is should have painted. This is actually caused by the other application receiving its WM_PAINT message after the data bar has been painted on top of it. This could be fixed by finding the window that is painting over the data bar and validating that region, or by windows hooks. However this option has been left unexplored. ConclusionThe WIN32 paint architecture has been designed to paint windows and controls
incrementally. This increases the performance and the appearance of applications.
The incremental paint process is enabled by the update region that WIN32 maintains
for each and every window. There are other types of common DCs that can be used to paint onto the window or
one of the displays. Each type of DC has a special purpose. The client DC is
is to paint on the client area of a window. Use the There are many different ways to paint a window in WIN32. This tutorial has presented many facts about the design, structure and process found in WIN32. Hopefully the reader can take these facts and apply them in ways that will increase the performance and appearance of his application.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||