I haven't posted it for a long time. Today it is itching, and I also send one. GDI's drawing function is basically stateful, and all functions require an HDC type handle. This HDC has several ways of beginpaint, getwindowdc, getdc. Their parameters only need a hwnd. I remember to call the endpaint after calling BeginpAint to clean up, and then adjust the ReleaseDC after calling getWindowDC and getDC. CDC CPAINTDC CWindowdc Cclientdc that is often encountered in the MFC code. Here is a slight explanation here. CDC: For example, use the GDI rectangular rectangle to rectangle (HDC, ...), and use the CDC is dc.Rectangle (...), which can be found that the CDC is mainly encapsulated by the GDI function originally required as a parameter. HDC became a member variable. CPAINTDC CWINDOWDC CCLIENTDC: They are inherited from CDC, which is to encapsulate the beginpaint, getWindowdc, and getdc calls mentioned above (CPAINTDC configuration calling beginpAint, and calling Endpaint, the rest). BeGinPaint is generally used in the response function to WM_PAINT to get the entire Window HDC, while GetDC can only get the HDC of the client area, the difference is that the former effectively draws the area is the entire window (border, title bar, The sum of the customer area). The latter effectively draws the area is limited to the customer area. The coordinate system of the two is relative coordinates rather than screen coordinates, the origin is (0, 0). That is, the upper left corner of the area can be drawn as the origin. Here, you can talk about RECT, RECT is a structure, and 4 members left, TOP, RIGHT, and BOTTOM are used to represent a rectangular area. CRECT is inherited from Rect, providing some common operations (such as displacement, reduction, etc.), in fact, the value of the four members. No CRECT is available at all. Many GDI functions require a RECT as a parameter, or similar (x, y, cx, cy) to parameters, in fact, a RECT variant, using width and height.
Basic knowledge is introduced, starting an instance tutorial: We use how to draw a state-of-a-style status bar: first inherited from CSTATUSBAR: CSTATUSBARNEW. (If you cannot do this by class wizard, and you are not familiar with MFC's MessageMap, you can inherit one from CSTATUSBARCTRL. After you make a code, change all CSTATUSBARCTRL to cstatusbar) here, only need to rewrite WM_PAINT and WM_ERASEBKGND The response function of these two messages. 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;} This function puts the status bar background with 0xF2f2f2 this color filled.
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) ); // Select the brush // Get font cfont * pfont = getFont (); cfont * def_font; if (pfont) DEF_FONT = cdc.selectObject (pfont); // Select the font cped pen; pen.createpen (ps_solid, 1, RGB (0xBD, 0xBA, 0xBD)); CPEN * POLDPEN = cdc.selectObject (& Pen); // Select a brush
CBRUSH BR (0x00F2F2F2); for (int i = 0; I / / Draw a rounded rectangular CDC.RoundRect for each panel; // Writing Uint nneWstyle = getPaneStyle (i); // If style is SBPS_DISABED, skip the not painted IF ((nnewstyle & sbps_disabled)! = 0) Continue; cstract text = getPaNtext (i); uint uformat = DT_SINGLINE | DT_NOPREFIX | DT_TOP | DT_LEFT; RCITEM.LEFT = 3; RcItem.top = 3; CDC.DrawText (Text, Rcitem, uformat);} if (pfont) cdc.selectObject (def_font); // Restore font // Draw a small sign of the right corner (six small circles here) IF (getStyle () & sbars_sizegrip {create 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 (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 brush } The above functions We can see the call of SelectObject multiple times, which is basically stateful. This state is saved in the HDC, while SelectObject sets the status of the HDC. It is commonly referred to as an option. What is the recovery in the comment? This is to be said from CPEN CBRUSH CFONT, and they are encapsulation of GDI objects. The GDI object is created by the Createpen Createbrush CreateFont, etc., returns a hgdiobj. These objects need to be destroyed while using the deleteObject function, but if a HGDiobj is selected into an HDC, it cannot be destroyed, which causes the leak of GDI resources. Solving this problem, there are usually two practices: The first one, that is, it is seen in the above code: first saved the original hgdiobj, def_font = cdc.selectObject (pfont); after using it, restore the original cdc.selectObject (def_font) In this way, it is guaranteed that PFont can be destroyed correctly. As for the original Def_Font, it is not possible to be destroyed. Second, the inventory object of the system is utilized. Inventory GDI object is pre-created in advance, no application is destroyed. So, you don't need to save the original HGDiobj, just like this SelectObject (hdc, :: getStockObject (null_brush)); or cdc.selectstockObject (null_brush); you can ensure that you have not selected in the HDC. These two methods are beneficial, and they are selected. In addition, most of the GDI functions are stateful, with an exception is a FillRect function, which is filled by a painted brush passed to him. Examples have been described, there are some additional skills: 1. GDI drawing skills learning: through reading, run, debug someone else's source code to obtain this path is the fastest. 2. The debugging of the GDI program Debugging GDI is generally difficult than other programs, but there is no obstacle to some skills. When debugging GDI, the IDE and the debugprous window are arranged separately on the desktop, do not overlap. This way you can perform the drawing effect of each step by single step. In order to cooperate with the above strategy, add the following sentence when the application is initialized: #ifdef _debug gdisetbatchlimit (1); # ENDIF This can guarantee that each GDI function call can now produce an effect at the time of debugging. Because Windows may process GDI calls in batches to performance optimization. 3. The memory drawing first understands the memory drawing, that is, draw the things you want to draw first in memory, and then draw a one-time painting to the screen. The memory drawing is often used to prevent flashing. Because flicker is because the contrast is too large. For example, your drawing process is first to erase the entire window with a white, then draw the black text to the screen, so when you re-draw, the original black text area will be bright, then the text, that is We have said it flashes. The process of memory drawing is first created a memory DC, and then painted the graphics to be drawn on this DC, then fill in the screen. The sample code is as follows: HDC HDestDC; Rect rc; // .. Received HDC and target RectHDC HDC = :: CreateCompatibleDC (HDestDC); hbitmap hbitmap = :: createcompatibleBitmap (HDestDC, rc.right, rc.bottom) Hbitmap HoldbitMap = :: SelectObject (HDC, HBitmap); // ... This is used to draw ///...::bitblt (m_HDESTDC, RC.LEFT, RC.TOP, RC.WIDTH (), RC . HEIGHT (), HDC, RC.LEFT, RC.TOP, SRCCOPY; :: SelectObject (HDC, HOLDBITMAP); of course, it is not convenient to use these operations to a CMEMDC, using these operations These operations are automatically made by constructors and sectations. There is also a benefit directly using CMEMDC. When you debug GDI, if the graphics are drawn in memory, then the drawing process is not seen. Code If you write: CRECT RC; getWindowRect (& rc); # ifdef _debug cpaintdc DC; #ELSE CPAINTDC CPDC; CMEMDC DC (CDC.m_HDC, & RC); # Endif, then enjoy the benefits of memory drawing and convenient to debugging . Getting started to write here, there is a work in writing in the future.