How to draw irregular forms using MFC
This article describes how to draw irregular forms using MFC. Share it with you for your reference. The specific analysis is as follows:
Implementation process:
1. Create a DLG-based MFC application named tryBGDlg, set the DLG attribute to Title Bar: False, and keep other settings unchanged.
2. Create two images, one of which is a black and white image based on the player's appearance. The white area is the area to be preserved and finally displayed on the desktop. Add the two images to the project. Set the first idnumber to IDB_INTERFACE, and the second idnumber to IDB_MASK.
3. Add a function in the CtryBGDlg class:
Function Description: cBitmap is the mask location variable to be passed in. Here it refers to the object created by IDB_MASK, and TransColor refers to the RGB value to be set as a transparent Prime.
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
Void CtryBGDlg: SetupRegion (CDC * pDC, CBitmap & cBitmap, COLORREF TransColor) { CDC memDC; MemDC. CreateCompatibleDC (pDC ); CBitmap * pOldMemBmp = NULL; POldMemBmp = memDC. SelectObject (& cBitmap ); BITMAP bit; CBitmap. GetBitmap (& bit ); CRgn crRgn, crRgnTmp; CrRgn. CreateRectRgn (0, 0, 0, 0); // create an empty area Int iX = 0; int iY = 0; For (iY = 0; iY <bit. bmHeight; iY ++) { Do { // Skip over transparent pixels at start of lines. While (iX <= bit. bmWidth & memDC. GetPixel (iX, iY) = TransColor) IX ++; // Remember this pixel Int iLeftX = iX; // Now find first non transparent pixel While (iX <= bit. bmWidth & memDC. GetPixel (iX, iY )! = TransColor) ++ IX; // Create a temp region on this info CrRgnTmp. CreateRectRgn (iLeftX, iY, iX, iY + 1 ); // Combine into main region. CrRgn. CombineRgn (& crRgn, & crRgnTmp, RGN_XOR ); // Delete the temp region for next pass (otherwise you'll get an ASSERT) CrRgnTmp. DeleteObject (); } While (iX <bit. bmWidth ); IX = 0; } Setjavaswrgn (crRgn, TRUE ); IX = (GetSystemMetrics (SM_CXSCREEN)-700; IY = (GetSystemMetrics (SM_CYSCREEN)/2-(bit. bmHeight/2 ); SetWindowPos (& wndTop, iX, iY, bit. bmWidth, bit. bmHeight, NULL ); // Free resources. MemDC. SelectObject (pOldMemBmp ); // Put the original bitmap back (prevents memory leaks) MemDC. DeleteDC (); CrRgn. DeleteObject (); } |
4. Add the following code to the BOOL CtryBGDlg: OnInitDialog () function:
?
1 2 3 |
CBitmap bmp; Bmp. LoadBitmapW (IDB_MASK ); This-> SetupRegion (this-> GetWindowDC (), bmp, RGB (0, 0 )); |
5. Add a message response to WM_ERASEBKGND and add the following code in the BOOL CtryBGDlg: OnEraseBkgnd (CDC * pDC) function:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
BOOL CtryBGDlg: OnEraseBkgnd (CDC * pDC) { // TODO: add the message processing program code and/or call the default value here CRect rect; This-> GetWindowRect (& rect ); CDC memDC; CBitmap bmp; CBitmap * pOldBmp = NULL; Bmp. LoadBitmapW (IDB_INTERFACE ); MemDC. CreateCompatibleDC (pDC ); POldBmp = memDC. SelectObject (& bmp ); PDC-> BitBlt (0, 0, rect. Width (), rect. Height (), & memDC, 0, 0, SRCCOPY ); If (pOldBmp) { MemDC. SelectObject (pOldBmp ); } Return true; // Return CDialog: OnEraseBkgnd (pDC ); } |
This allows you to create irregular forms. The created view is shown at the beginning.
6. Generally, we also need to perform the operation on the form. The implementation method is as follows:
Add a response to the WM_NCHITTEST message and add the following code in the generated LRESULT CtryBGDlg: OnNcHitTest (CPoint point) function:
?
1 2 3 4 5 6 7 8 9 |
LRESULT CtryBGDlg: OnNcHitTest (CPoint point) { // TODO: add the message processing program code and/or call the default value here CRect rc; GetClientRect (& rc ); ClientToScreen (& rc ); Return rc. PtInRect (point )? HTCAPTION: CDialog: OnNcHitTest (point ); // Return CDialog: OnNcHitTest (point ); } |
So far, it is fully implemented. The creation of irregular forms and the response to the form-initiated messages are complete.
The following describes the implementation principles and code analysis in detail:
General principle: the principle of this program is to first use the IDB_MASK image to calculate the outline of the form to be set, and then use the setw.wrgn () function to change it. Finally, the WM_ERASEBKGND message is returned when the window is weighed, and the IDB_INTERFACE of the form background image is pasted to the form.
The principle of using the IDB_MASK image to calculate the form profile is as follows:
The code for calculating the form outline is mainly implemented by the SetupRegion () function. Considering the irregular form, mask bitmap should be used to describe it. For this example, the white area is the contour area of the irregular form to be retained. This Code uses crRgn first. createRectRgn (0, 0, 0, 0) creates an empty area, and then enumerates the pixel information of the IDB_MASK image in a column, it is calculated that no transparent area is set in each column and then merged with crRgn. Therefore, the final crRgn is the area to be set.
The core code is:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
CRgn crRgn, crRgnTmp; // Create an empty region CrRgn. CreateRectRgn (0, 0, 0, 0 ); Int iX = 0; int iY = 0; For (iY = 0; iY <bit. bmHeight; iY ++) { Do { // Skip over transparent pixels at start of lines. // In the unit of a prime column, locate the first vertex iX that is not set to transparent prime in this prime column. // Then find the starting point of this iX. In this prime column, the last vertex nearest to him is not transparent. // Merge them into crRgn. While (iX <= bit. bmWidth & memDC. GetPixel (iX, iY) = TransColor) IX ++; // In the column iY and iY + 1, the X coordinate of the first vertex is not transparent. Int iLeftX = iX; // Save the coordinates of the vertex While (iX <= bit. bmWidth & memDC. GetPixel (iX, iY )! = TransColor) + + IX; // This is the X coordinate that finds the opacity nearest to iX. CrRgnTmp. CreateRectRgn (iLeftX, iY, iX, iY + 1); // these four points are the just-found opaque areas. // Merge Region CrRgn. CombineRgn (& crRgn, & crRgnTmp, RGN_OR ); // Remember to manually delete the crRgnTmp object CrRgnTmp. DeleteObject (); } While (iX <bit. bmWidth ); // If iX does not reach the end of the image, it indicates that this row has not been enumerated, then perform the next round of // enumeration on the line iY and iY + 1. IX = 0; } |
I hope this article will help you with the MFC program design.