Self-painted mfc buttons and mfc buttons

Source: Internet
Author: User

Self-painted mfc buttons and mfc buttons
 MFC button self-Painting

Author: songyanwu

If you are a god, you don't have to read this article!


Note: This article provides a simple self-painting button and also introduces self-painting. (It is definitely suitable for beginners. I also have a lot of Goolgle information, the introduction is rather vague. It also takes two days to organize and learn !) Although it is simple, it includes the principle of self-painting.



Source code download: mfc button self-Painting


Let's talk about some of my ideas: I want to encapsulate a button into a class, which is very convenient every time I use it. Of course, I can reload it in my class!


This article can be used as a reference for learning: MFC basics and MFC self-painted controls. (I also mainly studied the subclass method of the Self-painted control). After reading the previously recommended Article, how do you feel?

First, perform the following operations:


1. Create a painting box application. 2. Add a CMyButton to inherit from CButton3 and add messages WM_LBUTTONDOWN and WM_LBUTTONUP for your own classes. Then rewrite the DrawItem virtual function (called by the function from the painting ), 4. Add the Bool variable m_BtnDown to the class you added to determine the button status. 5. Add the message Code as follows:
<Span style = "font-size: 14px;"> void CMyButton: OnLButtonDown (UINT nFlags, CPoint point) {// TODO: add the message processing program code and/or call the default value m_BtnDown = true; Invalidate (); CButton: OnLButtonDown (nFlags, point);} </span>


<Span style = "font-size: 14px;"> void CMyButton: OnLButtonUp (UINT nFlags, CPoint point) {// TODO: add the message processing program code and/or call the default value m_BtnDown = false; Invalidate (); CButton: OnLButtonUp (nFlags, point);} </span>

Note: The Invalidate (BOOL bErase = TRUE) function is used to Invalidate the customer zone of the entire window. If the customer zone is invalid, it means that re-painting is required. For example, if a window that is covered by another window is changed to a front-end window, the previously hidden part is invalid and needs to be re-painted. In this case, Windows will place the WM_PAINT message in the message queue of the application. MFC provides the message processing function OnPaint of WM_PAINT for the window class. OnPaint is responsible for repainting the window. There are some exceptions to the View class. The OnDraw function is called in the OnPaint function of the View class, and the actual re-painting is completed by OnDraw. If the bErase parameter is TRUE, the background in the repainting area is erased. Otherwise, the background remains unchanged.

The difference between UpdateWindow and UpdateWindow is that UpdateWindow re-draws the window immediately. Invalidate only sends a WM_PAINT message. The priority of the WM_PAINT message is very low. The window will not be refreshed immediately until other messages in the message queue are processed.

When the window is re-painted, a button is re-generated, and its style is viewed when the button is generated. If the style is OwnerDraw, The DrawItem function is called. The OwnerDraw style settings will be discussed later.


6. Reload DramItem

<Span style = "font-size: 14px;"> void CMyButton: DrawItem (LPDRAWITEMSTRUCT lpDrawItemStruct/* lpDrawItemStruct */) {// TODO: add your code to draw the specified item // obtain the handle through the DRAWITEMSTRUCT structure and convert the type. This FromHandle is often used by CDC * pDC = CDC: FromHandle (lpDrawItemStruct-> hDC ); // The following two rows obtain the UINT state = lpDrawItemStruct-> itemState in this structure; // The status CRect rect = lpDrawItemStruct-> rcItem of the button; // The redraw range, that is, the text CString str displayed on the button // get button; GetWindowText (str); if (state & ODS_SELECTED) // If the button is selected {// draw a control and specify the control type and status pDC-> DrawFrameControl (& rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED );} else {pDC-> DrawFrameControl (& rect, DFC_BUTTON, DFCS_BUTTONPUSH);} if (m_BtnDown) {// fill the rectangle pDC-> FillSolidRect (rect, RGB (255,255, 0);} else {pDC-> FillSolidRect (rect, RGB (0, 0, 255);} if (! Str. isEmpty ()) {// The following figure shows the position of the text on the button to be moved slightly when the button is pressed. // calculate the width and length of a line of text in the current font to determine the size of CSize Extent = pDC-> GetTextExtent (str ); CPoint pt = CPoint (rect. centerPoint (). x-Extent.cx/2, rect. centerPoint (). y-Extent.cy/2); // if selected if (state & ODS_SELECTED) {// Add x, y coordinate pt to a point. offset ();} // set the background style. The value is: // The background is filled with the color of the current background before the text, brush, and pencil are painted. The Default background mode. // The background of TRANSPARENT remains unchanged before painting int nMode = pDC-> SetBkMode (TRANSPARENT); if (state & ODS_DISABLED) {pDC-> DrawState (pt, Extent, str, DSS_DISABLED, TRUE, 0, (HBRUSH) NULL);} else {pDC-> TextOut (pt. x, pt. y, str) ;}pdc-> SetBkMode (nMode) ;}</span>

Note:

1. The DrawItem function is used to redraw a single control. The parameter is a long pointer to DRAWITEMSTRUCT.

DRAWITEMSTRUCT provides necessary information for the control or menu item to be painted. Get a pointer to this structure in the WM_DRAWITEM message function corresponding to the control or menu item to be drawn.

2

<span style="font-size:14px;"> typedef struct tagDRAWITEMSTRUCT {         UINT CtlType;         UINT CtlID;           UINT itemID;         UINT itemAction;         UINT itemState;         HWND hwndItem;         HDC hDC;         RECT rcItem;         DWORD itemData;} DRAWITEMSTRUCT;</span><span style="font-size:14px;"></span>




CtlType: Specifies the parameter type. For example, ODT_BUTTON, ODT_COMBOBOX, and ODT_LISTBOX.

CtlID: combo box, list box, or button control ID. This parameter is not required for menu items

ItemID: the ID of a menu item. It can also represent the index value of an item in a list box or a combo box. For an empty list box or combo box, the value is-1. At this time, the application draws only the focus rectangle (the coordinates of the rectangle are given by the rcItem member ). Although the control does not need to be displayed at this time, it is necessary to draw the focus rectangle. This prompts you whether the control has the input focus. Of course, you can also set the itemAction value so that you do not need to draw the focus.

ItemAction: Specifies the draw action. multi-value is recommended. ODA_DRAWENTIRE: set this value when the entire control needs to be drawn. ODA_FOCUS: controls are drawn when they are obtained or de-focused. Check the itemState member to check whether the control has the input focus. ODA_SELECT: the control is repainted when the selected status changes. Check the itemState member to check whether the control is selected.

ItemState: Specifies the visible state of the painted items after the current painting is completed.

ODS_CHECKED: the menu item is selected. This value is only useful for menu items.

ODS_COMBOBOXEDIT: only the selected area is drawn in the Self-painted combo box control.

ODS_DEFAULT: default value.

ODS_DISABLED: this value is set if the control is disabled.

ODS_FOCUS: set this value if the control needs to enter focus.

ODS_GRAYED: the control is dimmed. This value is used only when the menu is drawn.

ODS_HOTLIGHT: Windows XP: If the mouse pointer is placed above the control, this value is set, and the control displays a highlighted color.

ODS_INACTIVE: Windows XP: indicates that no menu item is activated.

ODS_NOACCEL: Windows XP: whether the control has a quick keyboard.

ODS_NOFOCUSRECT: Windows XP, do not draw the capture focus effect.

ODS_SELECTED: The selected menu item.

HwndItem: Specifies the window handle of the Self-painted control, such as the combo box, list box, And button. If the self-painted object is a menu item, it indicates the menu handle containing the menu item.

HDC: Specifies the device environment Used for the painting operation.

RcItem: Specifies the area of the rectangle to be drawn. The rectangular area is the scope of the above hDC. The system will automatically crop parts outside the self-drawn Area of the control, such as the combo box, list box, or button. That is to say, the coordinate point (0, 0) in rcItem refers to the upper left corner of the control. However, the system does not crop a menu item. Therefore, when creating a menu item, you must first obtain the position of the menu item through a certain conversion to ensure that the painting operation is performed in the desired area.

3. DC (device context): A device context is a Windows data structure that contains information about drawing properties of a device (such as a display or printer. All painting calls are performed through device context objects that encapsulate Windows APIs for drawing lines, shapes, and texts. The device context allows you to draw a device-independent image in Windows. The device context can be used to draw to a screen, printer, or Metafile.

HDC is a DC handle of DC. CDC is the base class of all DC.

4. fromHandle (HANDLE h) Searches online to explain that it searches first. If h is associated with a CWnd (window) object, a pointer to this CWnd object is returned; if h is not associated with any CWnd object, a new CWnd object is returned.

7. Association Between Custom classes and standard controls

Method 1: Set the button property to Owner Drawn.

Method 2: Reload PreSubClassWindow in the program. This function is called after CWnd: Create and DDX_Contorl, that is, after the window subclass is created and before the window display. Add ModifyStyle (0, BS_OWNERDRAW) to this function. This function is used to change the control type.

8. Create a subclass self-painted button

Method 1: when creating a button, you can bind a CMyButton class object to this button, but this class cannot be seen in classwizard: You can delete the clw file in the current directory, then re-open the program, press ctrl + w, and generally select add all, click OK, and then add the class object, you will find this class.

Method 2: the above method is not suitable for dynamic addition.

Drag a Button control in the window. Add the member function CMyButton m_MyButton to the Dlg header file (note that you must add the header file ). Then, the OnInitDialog function in this window calls m_MyButton.SubClassDlgItem (IDC_BUTTON1, this). this function can dynamically subclass A Control created in this window and associate this control with CWnd.

If you already have a window pointer, or your work is in a CView or other CWnd derived class, and the control in it is dynamically created, or you do not want to use the above function, you can use the following methods.

CWnd * pWnd = GetDlgItem (IDC_BUTTON1 );
M_btnMyButton.SubclassWindow (pWnd-> GetSafeHwnd ());



You can download the code before! I will continue to learn other self-painting Applications later.



--------------------------------------------------------------------------------- Network arrangement --------------------------------------------------------------

I often encounter DrawItem () Rewriting in my studies, but there is another WM_DRAWITEM message. What is the relationship between them. If we want to rewrite a CButton to get the name CMyButton, we can rewrite the DrawItem () function of CMyButton to meet our needs, but when is the CMyButton: DrawItem () called? It is called in OnDrawItem () of its host class. OnDrawItem (int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) is the corresponding function for WM_DRAWiTEM. The host class can determine the child Control Based on nIDCtl. In fact, we can draw child controls in the OnDrawItem function, but many child controls do not look good, so we should draw child widgets in the DrawItem of the Child class, such as CMyButton: DrawItem. So it can be understood that OnDrawItem is the sub-control in the painting window, because its entry Parameter LPDRAWITEMSTRUCTYou must set the child control to the "self-painting" type before calling OnDrawItem. When the owner-draw button, combo box, list box visual attribute, or menu changes, the Framework calls OnDrawItem (send WM_DRAWITEM) for their owner and calls DrawItem (send WM_DRAWITEM message) of the subclass in the host class ). We can reload the DrawItem sub-class to draw the required controls. Not all controls set to the self-painting type will call the OnDrawItem of the parent window, such as ListBox self-painting, you must reload the DrawItem and MeasureItem methods of CListBox. However, self-painting like menus and buttons will call OnDrawItem. In the SDK, The subclass cannot be affected by WM_DRAWITEM. In MFC, this is designed by the class designer (reflection), which is indeed good.In learning, another message is also called by the host class, which is WM_CTRCOLOR. This message is sent to the host class when the child control is to be painted. The host class uses the emission mechanism to allow the Child class to process it again. OnCtlColor (CDC * pDC, CWnd * pWnd, UINT nCtlColor) pDC and pWnd are all related to sub-classes. You can set them here, including foreground color, background color, painter type, Font, etc, but it cannot change the interface framework of elements. This is what DrawItem can do. If DrawItem (subclass), OnDrawItem (host class), and OnCtlColor (host class) exist at the same time, their call sequence is OnCtlColor, OnDrawItem, and DrawItem. If we have processed the WM_PAINT message of the corresponding subclass at the same time, OnPaint may perform some processing internally to determine whether to send WM_DRAWITEM to the host class by self-painting, therefore, if the WM_PAINT subclass is responded, the WM_DRAWITEM message will not be sent to the host class. You need to complete the painting of the subclass. If the subclass is a list box, it will be very troublesome. The call sequence is OnCtlColor and OnPaint. Before sending a WM_PAINT message, a WM_ERASEBACK message will always be sent first. Here we have a background image. The above section describes how to draw controls at ordinary times. There is also a CView problem, that is, the relationship between OnPaint and Ondraw. In fact, this is very simple. CView: OnPaint () the source code is as follows: view plaincopy to clipboardprint?
Void CView: OnPaint ()
{
CPaintDC dc (this );
OnPrepareDC (& dc );
OnDraw (& dc)
} This article from the CSDN blog, reprint please indicate the source: http://blog.csdn.net/highfly4008/archive/2011/01/19/6152485.aspx
Reprint 2:

WM_DRAWITEM message

When the visible part of a button, combo box, list box, or menu with a self-painted style changes, the WM_DRAWITEM message is sent to the form of the Self-painted control.

1. It must be called when the control is created.

DrawItem (), but there is another WM_DRAWITEM message. What is the relationship between them.

If we want to override a CButton and name it CMyButton, we can rewrite the DrawItem () function of CMyButton to implement our

Yes, but when is the CMyButton: DrawItem () called? It is called in OnDrawItem () of its host class,

OnDrawItem (int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) is the corresponding function for WM_DRAWiTEM.

The host class can determine the child Control Based on nIDCtl. In fact, we can draw child controls in the OnDrawItem function, but there are many

The child control of the Child class looks bad, so we should plot the Child class in the DrawItem of the Child class, for example, CMyButton: DrawItem. So you can

In this way, OnDrawItem is the Child control in the painting window, because its entry parameter LPDRAWITEMSTRUCT brings the phase of different child Controls

You must set the word control to the "self-painting" type before calling OnDrawItem.





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.