Original] basic Windows GDI application (vc sdk)

Source: Internet
Author: User

Original] basic Windows GDI application (vc sdk)

 
I haven't posted a post for a long time. Today, my hand is itchy.
The drawing functions of GDI are basically stateful, and all functions require an HDC handle.
There are several ways to obtain this HDC: beginpaint, getwindowdc, and getdc. They only need one hwnd parameter.
Remember to call endpaint to clean up after beginpaint is called. Call getwindowdc and getdc to call releasedc to clean up.
The CDC cpaintdc cwindowdc cclientdc is often encountered in the MFC code. I will explain it here.
CDC: for example, if you use GDI to draw a rectangle, you must rectangle (HDC ,...), while using CDC is DC. rectangle (...), it can be seen that the CDC mainly encapsulates the GDI function that originally needed HDC as the parameter, and HDC becomes a member variable of it.
Cpaintdc cwindowdc cclientdc: They all inherit from the CDC, respectively, they encapsulate the aforementioned beginpaint, getwindowdc, getdc calls (beginpaint is called during cpaintdc construction, endpaint is called during structure analysis, others ).
Beginpaint is generally used in the response function of wm_paint.
Getwindowdc can obtain the HDC of the entire window, while getdc can only obtain the HDC of the customer zone. The difference is that ----
The former effectively draws the entire window (the sum of the border, title bar, and customer area ).
The latter effectively draws a region only for the customer zone.
The coordinates of the two are relative coordinates rather than screen coordinates. The origin is (0, 0 ). That is, use the upper left corner of the area you can draw as the origin point.
Here we can talk about rect. rect is a structure with four members left, top, right, and bottom in sequence to represent a rectangular area. Crect inherits from rect and provides some common operations (such as displacement and reduction). It actually changes the values of the four members. No need for crect. Many GDI functions require a rect as a parameter, or similarly use (X, Y, CX, CY) as a parameter, which is actually a rect variant, with both width and height.

After the basic knowledge is introduced, start the instance Tutorial:
Let's take how to draw a status bar with a flat style as an example:
First, inherit a class from cstatusbar: cstatusbarnew. (If you are not familiar with the messagemap and other things of MFC, You can inherit one from cstatusbarctrl. After the code is generated, change all cstatusbarctrl to cstatusbar)
Here, you only need to override the response functions of the two messages wm_paint and wm_erasebkgnd.
Bool cstatusbarnew: onerasebkgnd (CDC * PDC)
{
// Todo: add your message handler code here and/or call default
Crect rect;
Getwindowrect (& rect );
Screentoclient (& rect );
Cbrush brush (0xf2f2f2 );
PDC-> fillrect (& rect, & brush );
Return true;
}
This function fills the background of the status bar with the color 0xf2f2f2.

Void cstatusbarnew: onpaint ()
{
Cpaintdc CDC (this); // device context for painting
// Todo: add your message handler code here
Crect rcitem;
CDC. setbkmode (transparent );
CDC. SelectObject (: getstockobject (null_brush); // You can select a paint brush.

// Obtain the font
Cfont * pfont = getfont ();
Cfont * def_font;
If (pfont)
Def_font = CDC. SelectObject (pfont); // select the font

Cpen pen;
Pen. createpen (ps_solid, 1, RGB (0xbd, 0xba, 0xbd ));
Cpen * poldpen = CDC. SelectObject (& pen); // select the paint brush

Cbrush Br (0x00f2f2 );
For (INT I = 0; I <m_ncount; I ++)
{
Getitemrect (I, rcitem );
// Fill the Panel background
CDC. fillrect (rcitem, & Br );
Rcitem. Bottom --;
If (I = 0) rcitem. Left + = 2;

// Draw a rounded rectangle for each panel
CDC. roundrect (rcitem, cpoint (5, 5 ));

// Text on the canvas
Uint nnewstyle = getpanestyle (I );
// Skip if the style is sbps_disabled
If (nnewstyle & sbps_disabled )! = 0) continue;
Cstring text = getpanetext (I );
Uint uformat = dt_singleline | dt_noprefix | dt_top | dt_left;
Rcitem. Left + = 3;
Rcitem. Top + = 3;
CDC. drawtext (text, rcitem, uformat );
}
If (pfont)
CDC. SelectObject (def_font); // restore the font

// Draw a small sign in the lower right corner (six small circles are drawn here)
If (getstyle () & sbars_sizegrip)
{
Crect RC;
Getclientrect (& rc );
RC. Left = rcitem. Right;
RC. Right --;
RC. Bottom --;
RC. Left = RC. Right-RC. Width ()/4;
RC. Top = RC. Bottom-RC. Width ();
Int W = RC. Width ();
RC. Top ++;
RC. Left ++;
CDC. SelectObject (getstockobject (gray_brush ));
CDC. ellipse (& rc );
RC. offsetrect (-W,-W );
CDC. ellipse (& rc );
RC. offsetrect (W, 0 );
CDC. ellipse (& rc );
RC. offsetrect (-W, W );
CDC. ellipse (& rc );
RC. offsetrect (-W, 0 );
CDC. ellipse (& rc );
RC. offsetrect (2 * w,-2 * w );
CDC. ellipse (& rc );
}

CDC. SelectObject (poldpen); // restore the paint brush

}
We can see the call of SelectObject multiple times in the above function, which means that the previously mentioned drawing function is basically stateful.
This state is stored in HDC, while SelectObject sets the state of HDC. It is usually called "selector.
What is the recovery in the comment? This should start with cpen cbrush cfont and so on. They are encapsulation of GDI objects.
The GDI object is created using functions such as createpen createbrush createfont and returns a hgdiobj.
When these objects are not used, they must be destroyed. The deleteobject function is used. However, if an hgdiobj is selected into an HDC,
It cannot be destroyed, resulting in the leakage of GDI resources.
There are two solutions to this problem:
The first is what we see in the code above:
First save the original hgdiobj, def_font = CDC. SelectObject (pfont );
After it is used up, restore the original CDC. SelectObject (def_font );
This ensures that the pfont can be correctly destroyed. As for whether the original def_font can be destroyed, it is none of our work.
Second, the inventory objects of the system are used. Inventory GDI objects are pre-created in windows and do not need to be destroyed by applications.
Therefore, you do not need to save the original hgdiobj, just like this
SelectObject (HDC,: getstockobject (null_brush ));
Or CDC. selectstockobject (null_brush );
We can ensure that HDC is not selected for any paint brush we have created.
The two methods have their own advantages and are selected as needed.

In addition, most of the above-mentioned GDI functions are stateful. One exception is the fillrect function, which is filled by a painting brush sent to it.

After the instance is described, some additional skills are provided:
1. Learn the Drawing Technique of GDI: The Path to experience gained by reading, running, and debugging others' source code is the fastest.
2. debug the GDI Program
Debugging GDI is generally more difficult than other programs, but there is no obstacle to mastering some skills.
When debugging GDI, try to separate the IDE and debugging-on-behalf program windows on the desktop and do not overlap them.
In this way, you can view the drawing effect of each step by performing one step.
To work with the above policies, add the following sentence during application initialization:
# Ifdef _ debug
Gdisetbatchlimit (1 );
# Endif
This ensures that each GDI function call can immediately produce results during debugging. For performance optimization, windows may process GDI calls in batches.
3. Memory plotting
First, understand the memory drawing, that is, draw the items to be drawn in the memory first, and then draw them to the screen at one time. Memory plotting is often used to prevent flickering.
The reason for blinking is that the contrast is too large. For example, you need to first erase the entire window in white and then draw the black text on the screen,
In this way, when the window is re-painted, the original black text area will flash white, and then the text will appear again, that is, what we say flashes.
The memory drawing process is to first create a memory DC, then draw the image to be drawn on this DC, and then fill it on the screen at one time.
The sample code is as follows:
HDC hdestdc;
Rect RC;
// .. Obtain the target HDC and target rect.
HDC =: createcompatibledc (hdestdc );
Hbitmap =: createcompatiblebitmap (hdestdc, RC. Right, RC. Bottom );
Hbitmap holdbitmap =: SelectObject (HDC, hbitmap );
//... Use HDC for plotting.
//...
: Bitblt (m_hdestdc, RC. Left, RC. Top, RC. Width (), RC. Height (), HDC, RC. Left, RC. Top, srccopy );
: SelectObject (HDC, holdbitmap );
Of course, this is not easy to use. You can encapsulate these operations into an object named cmemdc and perform these operations automatically using the constructor and destructor.
Using cmemdc directly has another advantage: When debugging GDI, if the graphics are all drawn in the memory, you still cannot see the drawing process.
Write the Code as follows:
Crect RC;
Getwindowrect (& rc );
# Ifdef _ debug
Cpaintdc DC;
# Else
Cpaintdc CDC;
Cmemdc DC (CDC. m_hdc, & rc );
# Endif
Then you can enjoy the benefits of memory plotting and facilitate debugging.

This topic is written here first, and you will have time to write more advanced articles.
 
 
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.