A button with a pop-up menu can enable a button to have multiple options. by extending the button function, you can integrate multiple buttons to reduce the number of buttons.
The button body of this type of button is divided into two areas. When you click the main area, the main button function is executed. When you click Select area, a menu is displayed, from which you can select the function to be executed.
Next, let's take a look at its production process:
1. Create a New Class Based on the cbutton class
Click Insert> New Class to create a New Class. The base class is set to CButton, and the new class is named CMenuButton.
2. Draw a button using the self-painting method. The text of the button is displayed in the main area, and a small arrow is drawn in the selection area.
In the CMenuButton class, use ClassWizard to add functions: PreSubclassWindow () and DrawItem ().
The PreSubclassWindow () function is executed when the button is created. It can be used for preparation. Here I will add a custom property to the button:
Void CMenuButton: PreSubclassWindow ()
{
ModifyStyle (0, BS_OWNERDRAW); // set the button property to a self-painted style.
CButton: PreSubclassWindow ();
}
The DrawItem () function is used to draw buttons. The text on the left is used as the main area, and a small arrow is drawn on the right as the selection area. In practice, you can draw the desired shape and content based on your needs.
Void CMenuButton: DrawItem (LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC * pDC = CDC: FromHandle (lpDrawItemStruct-> hDC );
M_ButRect = lpDrawItemStruct-> rcItem; // obtain the button size
Int nSavedDC = pDC-> SaveDC ();
VERIFY (pDC );
DrawButton (pDC); // draw button
PDC-> RestoreDC (nSavedDC );
}
M_ButRect is a CRect object, which is defined in the header file. DrawButton () is a function used to draw a button. The purpose of defining it outside is to facilitate modification. To change the button shape, you only need to modify the DrawButton () function.
Void CMenuButton: DrawButton (CDC * pDC)
{
M_LRect.SetRect (m_ButRect.left, m_ButRect.top,
M_ButRect.right-21, m_ButRect.bottom); // button body area size
M_RRect.SetRect (m_ButRect.right-20, m_ButRect.top,
M_ButRect.right, m_ButRect.bottom); // the size of the button selection area.
CPen Pen;
Pen. CreatePen (PS_SOLID, 1, RGB (192,192,192 ));
PDC-> SelectObject (& Pen );
PDC-> FillSolidRect (m_ButRect, m_BackColor); // draw the background
Switch (m_State) // draw different borders in different States
{
Case 0: // normal button
PDC-> DrawEdge (& m_LRect, BDR_RAISEDINNER, BF_RECT );
PDC-> drawedge (& m_rrect, bdr_raisedinner, bf_rect );
Break;
Case 1: // the button when the mouse enters
PDC-> drawedge (& m_lrect, bdr_raisedinner, bf_rect );
PDC-> drawedge (& m_rrect, bdr_raisedinner, bf_rect );
PDC-> moveTo (m_butrect.topleft ());
PDC-> lineto (m_butrect.right, m_butrect.top );
Break;
Case 2: // click the button in the main area
PDC-> DrawEdge (& m_RRect, BDR_RAISEDINNER, BF_RECT );
Break;
Case 3: // click the area selection button
PDC-> DrawEdge (& m_LRect, BDR_RAISEDINNER, BF_RECT );
Break;
}
POINT m_pt [3], m_ptCentre; // arrow coordinate (three vertices)
M_ptCentre = m_RRect.CenterPoint (); // select the midpoint of the area
M_pt [0]. x = m_ptCentre.x-3; // calculates arrow coordinates
M_pt [0]. y = m_ptCentre.y-2;
M_pt [1]. x = m_ptcentre.x + 4;
M_pt [1]. Y = m_ptCentre.y-2;
M_pt [2]. x = m_ptcentre.x;
M_pt [2]. Y = m_ptcentre.y + 2;
PDC-> selectstockobject (black_brush); // defines the paint brush (black)
Crgn RGN;
RGN. createpolygonrgn (m_pt, 3, alternate );
PDC-> paintrgn (& RGN); // draw the arrow in the selection area
PDC-> settextcolor (m_forecolor); // draw text in the subject area
PDC-> setbkmode (transparent );
PDC-> drawtext (m_strtext, & m_lrect, dt_singleline | dt_center
| DT_VCENTER | DT_END_ELLIPSIS );
}
M_State is a flag. = 0 indicates the normal button; = 1 indicates the mouse enters the button and draws a dark line border; = 2 indicates the left mouse button is pressed in the button main area; = 3: Click the left mouse button in the button selection area.
Different button borders can be drawn under different values of m_State to increase the dynamic effect of buttons.
3. Add a mouse Response Function
In the CMenuButton class, use ClassWizard to add functions: OnMouseMove (), OnLButtonDown (), and OnLButtonUp ().
The OnMouseMove () function is used to respond to the mouse moving message. When the mouse enters the button, set the corresponding flag and redraw the button border. When the mouse leaves the button, clear the flag and restore the original border.
Void CMenuButton: OnMouseMove (UINT nFlags, CPoint point)
{
If (! B _InFlag | GetCapture ()! = This) // enter the mouse button
{
B _InFlag = true; // set the entry flag.
SetCapture (); // capture the mouse
M_state = 1; // set the button status (1-current button)
If (B _clickflag) // check the selection area flag
{
M_menu.detach (); // clear the menu
M_menu.destroymenu ();
B _clickflag = false;
}
Invalidate (); // redraw button
}
Else
{
If (! M_ButRect.PtInRect (point) // click the left button
{
B _InFlag = false; // clear the entry flag
ReleaseCapture (); // release Mouse capture
B _ClickBut = false; // clear the Click flag
M_State = 0; // set the button status (0-normal button)
If (B _ClickFlag) // check the selection area flag
{
M_Menu.Detach (); // clear the menu
M_Menu.DestroyMenu ();
B _ClickFlag = false;
}
Invalidate (); // redraw button
}
}
CButton: OnMouseMove (nFlags, point );
}
B _InFlag is a BOOL volume. It is set when the mouse enters and is cleared when it leaves. The purpose is to prevent repeated refresh buttons when the mouse moves on the button to avoid blinking.
B _ClickFlag indicates that the selection area icon is clicked. If it is set to true, the pop-up menu is opened. If it is set to false, the menu is not displayed. When the menu is displayed and the mouse moves back, clear the menu.
B _ClickBut is the identifier of the button subject area.
OnLButtonDown () function response button click the message. When you click the button body area, set the B _ClickBut flag. When you click the button to select a region, you need to decide whether to bring up the menu based on the number of clicks.
Void CMenuButton: OnLButtonDown (UINT nFlags, CPoint point)
{
If (m_LRect.PtInRect (point) // click the button in the main area
{
M_State = 2; // set the button status (2-normal button)
B _ClickBut = true; // set the button flag
Invalidate (); // redraw button
}
Else if (m_RRect.PtInRect (point) & m_MenuID) // click the selection area
{
M_State = 3;
B _ClickBut = false; // clear the button flag
Invalidate (); // redraw button
B _ClickFlag =! B _ClickFlag; // click the selection area flag.
If (B _ClickFlag) // click it at a time to bring up the menu
{
CRect rect = m_RRect;
Clienttoscreen (rect); // convert to screen coordinates
Point = rect. bottomright ();
Point. X-= rect. Width (); // you can specify the position of the pop-up menu.
Verify (m_menu.loadmenu (m_menuid); // load menu Resources
Cmenu * ppopup = m_menu.getsubmenu (0 );
Assert (ppopup! = NULL );
Cwnd * pwndpopupowner = this;
While (pWndPopupOwner-> GetStyle () & WS_CHILD)
PWndPopupOwner = pWndPopupOwner-> GetParent ();
PPopup-> TrackPopupMenu (TPM_LEFTALIGN | TPM_LEFTBUTTON,
Point. x, point. y, pWndPopupOwner); // The menu is displayed.
}
Else // Click again to clear the menu
{
M_Menu.Detach ();
M_Menu.DestroyMenu ();
}
}
CButton: OnLButtonDown (nFlags, point );
}
When you click the button to select a region, a menu is displayed in the lower left corner of the selection area. The point in the function is the screen coordinate of the mouse. screen coordinates are also used when you locate the menu.
M_MenuID is the ID of the pop-up menu associated with the button. It is set when the button is created.
The OnLButtonUp () function response button pops up the message. You only need to restore the button to its normal state to produce the animation effect.
Void CMenuButton: OnLButtonUp (UINT nFlags, CPoint point)
{
M_State = 0; // restore to normal button
Invalidate (); // redraw button
CButton: OnLButtonUp (nFlags, point );
}
Iv. User-Defined interface functions
Provides the interface for users to use buttons.
// Set the association menu ID
Void CMenuButton: SetMenuID (int nID)
{
M_MenuID = nID;
}
// Set button text
Void CMenuButton: SetText (CString str)
{
M_strText = str;
}
// Set the text color
Void CMenuButton: SetForeColor (COLORREF color)
{
M_ForeColor = color;
Invalidate ();
}
// Set the background color
Void CMenuButton: SetBkColor (COLORREF color)
{
M_BackColor = color;
Invalidate ();
}
// Whether to click the main button Area
BOOL CMenuButton: isClick ()
{
Return B _ClickBut;
}
This type of button is divided into two areas. The isClick () interface function is set according to the area to be clicked.
V. Variable Initialization
In the header file of the CMenuButton class, the following variables and functions are defined:
MenuButton. h
Private:
Int m_State; // button status
BOOL B _InFlag; // enter the cursor
BOOL B _ClickFlag; // click the selection area
BOOL B _ClickBut; // click the main area
CString m_strText; // button text
Colorref m_forecolor; // text color
Colorref m_backcolor; // background color
Crect m_butrect; // button size
Crect m_lrect; // left size of the button
Crect m_rrect; // right size of the button
Cmenu m_menu; // The menu is displayed.
Int m_menuid; // menu ID
Void drawbutton (CDC * PDC); // draw button
Public:
Cmenubutton (); // Constructor
Void setmenuid (int nid); // sets the association menu ID
Void setforecolor (colorref color); // sets the text color.
Void setbkcolor (colorref color); // sets the background color.
Void settext (cstring Str); // sets the button text
Bool isclick (); // whether to click the master button Area
Initialization of each variable is performed in the constructor:
Cmenubutton: cmenubutton ()
{
M_menuid = 0; // menu ID
B _InFlag = false; // enter the flag
M_State = 0; // initial state
B _ClickFlag = false; // click the selection area flag.
B _ClickBut = false; // click the subject area flag.
M_strText = _ T (""); // button text
M_ForeColor = RGB (0, 0); // text color
M_BackColor = GetSysColor (COLOR_3DFACE); // background color
}
In this way, the button class with a menu is ready, and the button instance defined by it can be connected to a pop-up button. Let's look at how to define the button instance.
6. Generate button instances
1. Place a button in the dialog box to adjust the size of the button;
2. Use ClassWizard to add a variable for the button and set the variable type to CMenuButton;
3. Define the associated menu of the button
The associated menu is a normal pop-up menu, which can be generated using the VC menu editor.
Enter the "Menu" item of the resource, insert a new Menu, and add a Menu item as needed.
4. Set button
In the oninitial () function of the dialog box, initialize the button:
Button variable. setmenuid (menu ID );
Button variable. settext (button text );
Button variable. setbkcolor (Button background color );
7. Button response
The response to the button consists of the response of the clicked button main area and the response of the clicked menu item.
Use classwizard to add the response function of the button and the response function of each menu item.
In the response function of the button, do the following:
Void cmbtestview: onmenubutton1 ()
{
If (m_menubutton1.isclick ())
{
// Response button operation
}
}
The response is required only when the subject area of the button is clicked.
As for the response of clicking a menu item, it is not detailed here.
There are several improvements to this button class:
① Add the invalid status (dimmed) button;
② Set the button text font.
For more information, see "buttons for setting fonts and colors".