MFC dynamically creates controls and adds message responsesCategory: Control technology 2013-01-24 14:12 7020 people read reviews (0) favorite reports
Reprint Address: http://blog.csdn.net/luy3728000/article/details/8193918
A dynamic control is a control created by create () when needed, unlike a control placed in a dialog box beforehand.
First, create a dynamic control:
For the sake of comparison, let's take a look at the creation of static controls.
When you place a static control, you must first create a container, usually a dialog box, when we drag the desired control from the tool window into the dialog box in the Dialog editor window, modify the control ID appropriately, set the control property, and a static control is created, and the controls on it are displayed when the dialog box is displayed.
Static controls do not need to call the Create () function for creation.
While creating dynamic controls is a big difference, here's an example of a button to look at the creation of a dynamic control:
1. Build the control ID number:
The ID number is the identity of the control, and you must set an ID number for it before creating the control.
Open the String table in the resource, double-click on a blank line, and an ID property dialog pops up, enter the ID in the ID edit box, such as: Idc_mybutton, enter the control title or annotation in caption (Note: the caption box cannot be empty, Null will cause the creation to fail), here I enter the button to display the text-the dynamic button.
2. Create the Control object:
Different kinds of controls should create different class objects:
• Button controls CButton (including normal buttons, radio buttons, and check buttons)
• Edit Control CEdit
• Static Text control CStatic
• Label Control CTabCtrl
• Rotation Control CSpinButtonCtrl
• Sliding Label Control CSliderCtrl
• Multi-information editing controls CRichEditCtrl
• Progress bar control CProgressCtrl
• Scroll bar control Csrcollbar
• Combo box control CComboBox
• List box control CListBox
• Image List Control Cimagectrl
• Tree-shaped controls CTreeCtrl
• Animated Controls CAnimateCtrl
In this example we create a normal button for the CButton class. Note You cannot define CButton objects directly, such as: CButton m_mybut; This definition can only be used to define control variables for static controls and not for dynamic controls.
The correct approach is to call the CButton constructor with new to generate an instance:
CButton *p_mybut = new CButton (); |
It is then created with the Create () function of the CButton class, the function prototype is as follows:
BOOL Create (LPCTSTR lpszcaption, DWORD dwstyle, const rect& RECT, cwnd* pParentWnd, UINT NID); |
Lpszcaption is the text displayed on the button, Dwstyle specifies the button style, which can be a combination of the button style and the window style, with the following values:
Window style:
· Ws_child child window, must have
· ws_visible window is visible, generally have
· ws_disabled Disable the window, create a button when the initial state is dimmed is used
· Ws_tabstop available Tab key selection
· Ws_group, the first button in a group of radio buttons
Button style:
Bs_pushbutton Push-button, also known as the normal button
Bs_autoradiobutton radio buttons with auto-check status
Bs_radiobutton radio button, not commonly used
bs_autocheckbox Check button with auto-check status
bs_checkbox Check button, not used
bs_auto3state Tri-state check button with auto-check status
bs_3state Three-state check button, not commonly used
The above style specifies the type of button created and cannot be used at the same time, but must be one.
The bitmap is displayed on the bs_bitmap button
Bs_defpushbutton is set as the default button, only for the push button, only one default button can be specified in a dialog box
rect Specifies the size and position of the button;
pParentWnd indicates the parent window that owns the button and cannot be null;
NID specifies the ID number associated with the button, using the ID number created in the previous step.
The Create () function for different control classes is slightly different, so you can refer to the relevant data.
Example: P_mybut->create ("Dynamic button", Ws_child | ws_visible | Bs_pushbutton, CRect (20,10,80,40), this, Idc_mybutton);
In this way, we create a push button with a width of 60, a height of 30, and a button text of "Dynamic button" at (20,10) in the current dialog box.
To make the creation process more user-friendly, I defined the following functions:
cbutton* Ctexteditorview::newmybutton (int nid,crect rect,int nstyle) { CString m_caption; M_caption.loadstring (NID); Take button title CButton *p_button = new CButton (); Assert_valid (P_button); P_button->create (m_caption, Ws_child | ws_visible | Bs_pushbutton | Nstyle, rect, this, NID); Create button return P_button; } |
where M_caption.loadstring (NID) reads the button text from the string table so that when the button ID is created, the text should be set, and the parameter nstyle as an extra style beyond the style that must be styled.
Following, call this function to create three buttons in Oniniatial and specify the first button as the default button, the ID of the button is pre-set in string table:
CButton *p_mybtn[3];//in order to release resources later, instead of declaring them in the class header file as Public variables P_mybtn[0]=newmybutton (Id_mybtn1,crect (10,20,60,40), Bs_defpushbutton); P_mybtn[1]=newmybutton (Id_mybtn2,crect (10,50,60,70), 0); P_mybtn[2]=newmybutton (Id_mybtn3,crect (10,80,60,100), 0); |
Second, the response of the dynamic control:
The response function of a dynamic control cannot be added with ClassWizard, but can only be added manually. Still with the above button as an example, we make a click response function for the button.
1. Add the response function in Message_map:
The message response function is defined in the Message_map table in the form of a message name (ID, function name), which is automatically added to the interval enclosed in afx_msg_map when we add a function with ClassWizard, such as:
Begin_message_map (Ctexteditorview, CFormView) {{Afx_msg_map (Ctexteditorview) On_bn_clicked (idc_iconbut0, OnIconbut0) }}afx_msg_map End_message_map () |
Do not add to the Afx_msg_map interval when manually added, in case ClassWizard does not work properly, such as:
Begin_message_map (Ctexteditorview, CFormView) {{Afx_msg_map (Ctexteditorview) On_bn_clicked (idc_iconbut0, OnIconbut0) }}afx_msg_map On_bn_clicked (ID_MYBTN1, ONMYBTN1) On_bn_clicked (ID_MYBTN2, ONMYBTN2) On_bn_clicked (Id_mybtn3, ONMYBTN3) End_message_map () |
Where on_bn_clicked is a button click message.
2. Add the function definition to the header file:
When you add a function with ClassWizard, a function definition is added within the afx_msg interval of the header file, such as:
Protected {{afx_msg (Ctexteditorview) afx_msg void OnIconbut0 (); }}afx_msg Declare_message_map () |
We imitate this form, just add the function definition to the afx_msg interval:
Protected {{afx_msg (Ctexteditorview) afx_msg void OnIconbut0 (); }}afx_msg afx_msg void OnMybtn1 (); afx_msg void OnMybtn2 (); afx_msg void OnMybtn3 (); Declare_message_map () |
3. Write the message response function:
The above is to associate the message and function, the specific work to do after clicking the button is done in the function:
void Ctexteditorview::onmybtn1 () { MessageBox ("Ha! You clicked the dynamic button. " ); } void Ctexteditorview::onmybtn2 () { ...... } void Ctexteditorview::onmybtn3 () { ...... } |
In addition to the button's response function, you can also use the pointer access buttons above, such as:
Modify the size and position of the button: P_mybtn[0]->movewindow (...);
Modify button text: P_mybtn[0]->setwindowtext (...);
Show/Hide button: P_mybtn[0]->showwindow (...); Wait a minute.
Third, recycling resources:
Because the dynamic control object is generated by new, it is not automatically freed by the program, so it needs to be freed manually. You can delete a control when it is no longer in use and destroy it in a destructor in a dialog box (destructors are not added manually):
Cmonthcalctrldlg::~cmonthcalctrldlg () { for (int i=0;i<3;i++) {if (P_mybtn[i]) Delete P_mybtn[i]; p_mybtn[0]=null;//if the other way to release, then add this sentence, otherwise it will be wrong } } |
These are the methods that the button control dynamically generates.
Implementation of the VC custom Picture button control
(reproduced) The framework of the Gobang program has been written before, the whole background of the program is I use Photoshop, of course, including a few buttons.
Said is the button, is actually the picture button, and the VC button control is completely different, but at that time I want to let the picture button also responds to mouse action such as mouse move to the button, mouse click, method is very stupid, is in the main dialog box mouse movement and click action to detect, if the occurrence position is located in the button area, in the Button "area to attach another picture to achieve the effect of the mouse on it, click Similar.
For multiple buttons, it is necessary to detect multiple areas, the program is very complex, and performance is poor.
So want to rewrite the VC CButton class, to achieve my function. On the internet to check a lot of information, is to say how to display a picture on the button, can display but also has the original button border, dashed. You have to write it yourself.
Requirements:
1. Dynamically generate a Picture button, function input Two images of the ID, and the button coordinates and size, most importantly, the order hit it to the parent window to pass the message value (custom)
2. When the mouse is over the button, the Picture button changes to a different picture, which is compared with the image in normal state.
3. When the mouse clicks this button, the parent window gets the message value specified for the window when it is initialized so that the response is differentiated when there are multiple buttons present
Process:
1. Derive the Cmybtn class from the CButton class, adding the following variables:
enum {state_mouseon, state_normal}; Defining button states
CBitmap M_pbmp1, m_pbmp2;//load two pictures
CRect M_RC; Save Button Client Area
int m_state; The button is in the state of enum two values, representing the mouse on the button and under normal circumstances
BOOL M_istimeron; Timer open No, used to determine the relative position of the mouse and button
Point M_cursorpos; Mouse position
2. The CREATE function of the CButton class is overloaded because you specify the image ID, the button coordinate size, and the message value when creating a custom button dynamically.
BOOL cmybtn::create (UINT idbitmapnomal, uint idbitmapmouseon, uint msg,
LPCTSTR lpszcaption, DWORD dwstyle, const rect& RECT, cwnd* pParentWnd, UINT NID)
Reload Create, which specifies the picture that the button should display in two states, and the message that is passed to the parent window when clicked
{
Todo:add your specialized code here and/or call the base class
M_pbmp1.loadbitmap (Idbitmapnomal);
M_pbmp2.loadbitmap (Idbitmapmouseon);
Variable initialization
M_istimeron = FALSE;
M_state = State_normal;
M_message = msg;
Return Cbutton::create (Lpszcaption, Dwstyle, rect, pParentWnd, NID);
}
3. To redraw the button to set the button type to Bs_ownerdraw, overload the Presubclasswindow function
void cmybtn::P Resubclasswindow ()
{
Todo:add your specialized code here and/or call the base class
ModifyStyle (0, Bs_ownerdraw|bs_pushbutton);
CButton::P Resubclasswindow ();
}
4. Then redraw the button and reload the DrawItem function
void cmybtn::D rawitem (lpdrawitemstruct lpdrawitemstruct)
{
Todo:add your code to draw the specified item
GetClientRect (&M_RC); Get a valid rectangular area of a button window
CDC *PDC = Cdc::fromhandle (LPDRAWITEMSTRUCT->HDC); Gets the device variable pointer for the button control customer area
CDC MEMDC;
Memdc.createcompatibledc (PDC);
CBitmap * pBmp = NULL;
if (State_normal = = m_state)
{
PBMP = Memdc.selectobject (&M_PBMP1);
}
if (State_mouseon = = m_state)
{
PBMP = Memdc.selectobject (&M_PBMP2);
}
Pdc->bitblt (M_rc.left, M_rc.top, M_rc.right, M_rc.bottom, &MEMDC, 0, 0, srccopy);
PBMP = Memdc.selectobject (PBMP);
}
5. Determine if the mouse is in the button area of the method is, if the mouse moves in the button area, set a timer, the mouse position tracking detection, if the set M_state is State_mouseon, otherwise set to State_normal. Then the entire client area is invalidated for repainting.
void Cmybtn::onmousemove (UINT nflags, CPoint Point)
{
Todo:add your message handler code here and/or call default
if (!m_istimeron)
{
SetTimer (10000, +, NULL);
M_istimeron = TRUE;
}
Cbutton::onmousemove (nflags, point);
}
void Cmybtn::ontimer (UINT nidevent)
{
Todo:add your message handler code here and/or call default
CRect rect;
GetWindowRect (&rect); Get the screen coordinate position of the button client area
GetCursorPos (&m_cursorpos); Get the screen coordinate position of the mouse
if (rect. PtInRect (M_cursorpos))//If the mouse is within the client area of the button
{
if (State_mouseon! = m_state)
{
M_state = State_mouseon;
Invalidate ();
}
}
else//mouse away button client area
{
if (state_normal! = m_state)
{
M_state = State_normal;
Invalidate ();
}
KillTimer (nidevent);
M_istimeron = FALSE;
}
Cbutton::ontimer (nidevent);
}
6. In response to a click, the M_message message is passed to the parent window, whose value is specified by the parent window when create.
void Cmybtn::onlbuttonup (UINT nflags, CPoint Point)
{
Todo:add your message handler code here and/or call default
GetParent ()->postmessage (m_message);
Cbutton::onlbuttonup (nflags, point);
}
Attached: Implementation of VC Custom message response
First step: Define the message. When developing WINDOWS95 applications, Microsoft recommends that user-defined messages be at least wm_user+100, because many new controls also use Wm_user messages.
Step two: Implement the message handler function. The function uses the Wpram and lparam parameters and returns Lpesult.
Lpesult cmainframe::onmymessage (WPARAM WPARAM, LPARAM LPARAM)
{
TODO: Handling User Custom messages
...
return 0;
}
Step three: Describe the message handler function in the afx_msg block of the class header file:
Class Cmainframe:public CMDIFrameWnd
{
...
General Message Mapping functions
Protected
{{afx_msg (CMainFrame)
afx_msg int OnCreate (lpcreatestruct lpcreatestruct);
afx_msg void OnTimer (UINT nidevent);
afx_msg LRESULT onmymessage (WPARAM WPARAM, LPARAM LPARAM);
}}afx_msg
Declare_message_map ()
}
Fourth step: In the message block of the user class, use the ON_MESSAGE macro directive to map the message to the message handler function.
Begin_message_map (CMainFrame, CMDIFrameWnd)
{{Afx_msg_map (CMainFrame)
On_wm_create ()
On_wm_timer ()
On_message (Wm_my_message, OnMyMessage)
}}afx_msg_map
End_message_map ()
If the user needs an entire system-unique message, you can call the SDK function RegisterWindowMessage and replace the ON_MESSAGE macro with the On_register_message macro directive, as in the remaining steps.
MFC dynamically creates controls and adds message responses