VC ++ in-depth explanation (2): MFC message ing and Basic Drawing

Source: Internet
Author: User

Let's take a look at a simple example: Let the program respond to a MessageBox with the left mouse button.

There are two ways to complete this task: 1. Select Add Windows message handler on the corresponding class, select wm_lbuttondown message, add a processing function, and add a sentence to the processing function:

MessageBox("view click!");

You can also choose View> Create Class Wizard from the menu. Under message maps, select project to select this project, class name to select this class from cxxvew, Object ID, and message to select wm_lbuttondown, then add a function.
Note that no matter whether classwizard or add windows message handler is used, code will be added in three places:
1. Class header file:

//{{AFX_MSG(CCH_4_DRAWView)afx_msg void OnLButtonDown(UINT nFlags, CPoint point);//}}AFX_MSG

Afx_msg is called a comment macro, and the programs between them are grayed out, indicating that the message response functions are declared between them.

2. Add a message ing macro to the class source file:

BEGIN_MESSAGE_MAP(CCH_4_DRAWApp, CWinApp)//{{AFX_MSG_MAP(CCH_4_DRAWApp)ON_COMMAND(ID_APP_ABOUT, OnAppAbout)// NOTE - the ClassWizard will add and remove mapping macros here.//    DO NOT EDIT what you see in these blocks of generated code!//}}AFX_MSG_MAP// Standard file based document commandsON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)// Standard print setup commandON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)END_MESSAGE_MAP()

3. Message Response Functions

void CCH_4_DRAWView::OnLButtonDown(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultMessageBox("view click!");CView::OnLButtonDown(nFlags, point);}

Therefore, if you want to delete some content, you should select Delete on the corresponding message processing function instead of manually deleting it.
When we see the above code, we can't help but ask: In the SDK, switch... is used ...... The meaning of the case statement is clear, but how is message ing implemented here?
There are two optional mechanisms:
1. Use virtual functions: Define a virtual function for each message processing function in the base class. You can override these functions in the derived class. However, this method is not desirable, because we know that virtual functions must be implemented through virtual function tables. In the complicated inheritance and derivation System of MFC, adding a virtual function table for each class will greatly increase the overhead of the entire program, and scanning the virtual function table will consume a lot of time.
2. Use the message ing table. For each class that can receive and process messages, define a static comparison table between messages and message functions. When a message arrives, you only need to scan the table to determine whether the class can process the message. If the child class cannot find the message response function, it is handed over to the base class for processing.

Next we will illustrate message ing through simple drawing examples. First, let's review the drawing under the SDK. There are three basic methods:
1. Use setpixel to set a color for a certain pixel, and use getpixel to obtain a certain color.
2. Use movetoex to move to a certain point, and use lineto to draw from the current point to the specified point.
3. Use some basic drawing functions provided by windows, such as rectangle, ellipse, and roundrect.
One important concept related to drawing is DC (device description table, device context) and corresponding handle HDC. In MFC, we will still use them.

Let's get down to the truth and start drawing: Start with drawing a line:
We found that the onlbuttondown function returns a cpoint object, which indicates the specific position of the point where the mouse is pressed. Therefore, we can add a cpoint member m_ptorigin for our view class to save this point (note that, in habits, we start with M _ for member variables ).

void CCH_4_DRAWView::OnLButtonDown(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call default//MessageBox("view click!");m_ptOrigin = point;CView::OnLButtonDown(nFlags, point);}

When the left mouse button pops up, the terminal coordinates are obtained. Therefore, we need to add a response function for wm_lbuttonup. In this case, we can use either the traditional approach under the plantform SDK or the practice under the MFC.

void CCH_4_DRAWView::OnLButtonUp(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultHDC hdc;hdc = ::GetDC(m_hWnd);MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);LineTo(hdc,point.x,point.y);::ReleaseDC(m_hWnd,hdc);CView::OnLButtonUp(nFlags, point);}

Note: In the cwnd of the base class cview of our view class, the Public Member hwnd m_hwnd has been defined; in this case, a normal call is required.
The following describes the MFC method. MFC encapsulates the device description table and converts it to the specific usage of CDC as follows:

CDC* pDC = GetDC();pDC->MoveTo(m_ptOrigin);pDC->LineTo(point);ReleaseDC(pDC);

Define a pointer to the CDC, call the getdc () function to obtain the pointer to the context of the current device, and draw a line through the member function. We found that because m_hwnd is set as a member variable, we do not need to pass this variable in the function.
Here, we can only draw images in the view. Similar to the program under the SDK, our drawing can be extended to the entire customer area, the entire window, and even the entire screen. It depends on what Dc you get:

CClientDC dc(this);dc.MoveTo(m_ptOrigin);dc.LineTo(point);

Note that the getdc-related operations and releasedc operations are not used here, because they are automatically completed in the constructor and destructor of the class. This is an idea of "Object-based resource management". To some extent, it can avoid Memory leakage caused by exceptions before releasedc. Once an exception occurs, the DC will be released, and resources can be recycled by calling the Destructor when the exception is released.
To draw a line on the toolbar, you must obtain the handle of the frame window:

CClientDC dc(GetParent());

To draw the entire window, you need to use the cwindow class:

CWindowDC dc(GetParent());

If you want to draw on the entire desktop, You need to obtain the DC of the desktop:

CWindowDC dc(GetDesktopWindow());

Although the position is not very satisfactory, it is better than nothing.
Next let's take a look at how to modify the color of the paint brush. The idea here is the same as that in the SDK. Define a paint brush to select its color, width, and so on, and then select it into the device description table.

CClientDC dc(this);CPen pen(PS_SOLID,1,RGB(255,0,0));CPen* pOldPen = dc.SelectObject(&pen);dc.MoveTo(m_ptOrigin);dc.LineTo(point);dc.SelectObject(pOldPen);

Note: in practice, after we draw a line, we need to restore the linear and color to the previous state.
The following describes how to use a brush.

CBrush brush(RGB(255,0,0));CClientDC dc(this);dc.FillRect(CRect(m_ptOrigin,point),&brush);

First, define an object of the brush type. After obtaining the device context, use the fillrect function to use the brush. This function accepts two parameters. The first parameter is a pointer to a rectangle, the second parameter is the pointer to the brush. However, the first parameter used in the program is a rectangle constructed from two points without an address. Why? The reason is that the crect class reloads the lpcrect () operator. Here, this overload function can be called automatically without the address.
The brush also has a constructor that accepts the pointer to the bitmap: cbrush (cbitmap * pbitmap). We can create a new bitmap, load the bitmap, and use the bitmap to construct the brush.

CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP1);CBrush brush(&bitmap);CClientDC dc(this);dc.FillRect(CRect(m_ptOrigin,point),&brush);

It should be noted that when our white paint brush is not transparent, it will block each other. If we want to draw a transparent rectangle, it will take a great deal. Because the cbrush class does not provide a transparent image brush function. But we know that in the getstockobject function, you can select hollow_brush or null_brush to represent a hollow brush. So how can we combine them?

CClientDC dc(this);CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));CBrush *pOldBrush = dc.SelectObject(pBrush);dc.Rectangle(CRect(m_ptOrigin,point));dc.SelectObject(pOldBrush);

The fromhandle function is called, which converts a brush in Windows GDI into a pointer to a cbrush. It is worth noting that this function is a static function, so it is called through an object.
Finally, we will make a simple comparison between the rectangle function and the fillrect function. They all draw rectangles, but because the fillrect function needs to specify which brush to use, therefore, you do not need to use the SelectObject function to determine the image brush.

Next we will look at how to draw continuous lines.
The key to this problem is to capture the wm_mousemove message, but it is not just to draw a line as long as the mouse moves. What you want is to press the mouse down and start to draw a line, then release it and stop the draw line. You need a variable to record whether the mouse is pressed. When wm_lbuttondown is recorded, the mouse is pressed, and when wm_lbuttonup is recorded, the mouse pops up. When processing the wm_mousemove message function, first judge whether the variable pressed by the mouse is true. We name this variable m_bdraw and initialize it to false in the constructor. The program that responds to the wm_mousemove message is:

void CCH_4_DRAWView::OnMouseMove(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultCClientDC dc(this);if(TRUE == m_bDraw){dc.MoveTo(m_ptOrigin);dc.LineTo(point);m_ptOrigin = point;}CView::OnMouseMove(nFlags, point);}


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.