MFC动态创建CEdit控件
MFC动态创建CEdit控件
在项目开发时,可能遇到动态创建控件的情况。如根据当前用户的数量,动态创建控件显示用户信息等情况,需要动态常见静态文本框和编辑框等。
此时,利用控件类中Create()函数进行动态创建,默认是显示状态。如:
头文件定义:CStatic *p_MyStatic;
CPP中实现:
p_MyStatic = new CStatic();
p_MyStatic->Create("静态文本框",WS_CHILD|WS_VISIBLE|SS_CENTER,CRect(0,i*perHeight+5,perWidth,(i+1)*perHeight+5),this);
在退出时:
if(pStatic!=NULL)
delete pStatic;
对于单个或者固定数量的控件可以使用指针数组CStatic *p_MyStatic[TOTALCOUTS]照此进行。
但当TOTALCOUTS不固定时,可以使用MFC中CPtrArray进行开发,CPtrArray是一个链表类,用于保存动态创建的控件地址。
实现如下图所示的界面。
下面附上具体的代码:
- // DynamicMultiCtrlsDlg.h : 头文件
- #define EDIT_ID 10000
- public:
- CPtrArray p_MyStatics;
- CPtrArray p_MyEdits;
在点击创建时的具体执行代码如下:
- void CDynamicMultiCtrlsDlg::OnBnClickedBtnCreate()
- {
- // TODO: 在此添加控件通知处理程序代码
- CString m_staticCaption;
- CRect rect,rect2;
- GetClientRect(&rect);
- GetDlgItem(IDOK)->GetWindowRect(&rect2);
- ScreenToClient(&rect2);
- int m_counts =21;
- int perWidth = rect.Width()/4;
- int perHeight =rect2.top/m_counts;
- CStatic *p_MyStatic;
- CEdit *p_MyEdit;
- for(int i=0;i<m_counts;i++)
- {
- p_MyStatic = new CStatic();
- p_MyEdit = new CEdit();
- m_staticCaption.Format("第%d台IP地址:",i+1);
- if(i%2==0)
- {
- p_MyStatic->Create(m_staticCaption,WS_CHILD|WS_VISIBLE|SS_CENTER,CRect(0,i*perHeight+5,perWidth,(i+1)*perHeight+5),this);
- m_staticCaption.Format("%d台IP",i+1);
- p_MyEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER,CRect(perWidth,i*perHeight+5,perWidth*2,(i+1)*perHeight+5),this,EDIT_ID+i);
- p_MyEdit->SetWindowText(m_staticCaption);
- if(p_MyStatic!=NULL)
- {
- p_MyStatics.Add((void*)p_MyStatic);
- // delete p_MyStatic;
- }
- if(p_MyEdit!=NULL)
- {
- p_MyEdits.Add((void*)p_MyEdit);
- // delete p_MyEdit;
- }
- }else
- {
- p_MyStatic->Create(m_staticCaption,WS_CHILD|WS_VISIBLE|SS_CENTER,CRect(perWidth*2,(i-1)*perHeight+5,perWidth*3,i*perHeight+5),this);
- m_staticCaption.Format("%d台IP",i+1);
- p_MyEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER,CRect(perWidth*3,(i-1)*perHeight+5,perWidth*4,i*perHeight+5),this,EDIT_ID+i);
- p_MyEdit->SetWindowText(m_staticCaption);
- if(p_MyStatic!=NULL)
- {
- p_MyStatics.Add((void*)p_MyStatic);
- //delete p_MyStatic;
- }
- if(p_MyEdit!=NULL)
- {
- p_MyEdits.Add((void*)p_MyEdit);
- // delete p_MyEdit;
- }
- }
- }
- }
- 在有new的时候记得在程序退出时,delete掉所有new的指针
- void CDynamicMultiCtrlsDlg::OnClose()
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- int n=p_MyStatics.GetSize();
- for(int i=0;i<n;i++)
- {
- CStatic* pStatic=(CStatic*)p_MyStatics.GetAt(i);
- // pStatic->DestroyWindow();
- if(pStatic!=NULL)
- delete pStatic;
- p_MyStatics[i]=NULL;
- }
- p_MyStatics.RemoveAll();
- n=p_MyEdits.GetSize();
- for(int i=0;i<n;i++)
- {
- CEdit* pEdit=(CEdit*)p_MyEdits.GetAt(i);
- //pEdit->DestroyWindow();
- if(pEdit!=NULL)
- delete pEdit;
- p_MyEdits[i]=NULL;
- }
- p_MyEdits.RemoveAll();
- CDialogEx::OnClose();
- }
如在1和2的地方,我用了new,所以在总是在3和4的地方要把它们统统delete掉。可是这样导致了创建的控件无法显示。
为什么呢?
因为我把new出来的控件指针delete掉了,能显示出来才奇怪。
但是,不delete掉不会造成内存泄漏吗?
这个我在论坛发帖求助的时候,突然有个这样的理解:new出来的控件地址,已经全部保存到了CPtrArray链表中,而且在程序Close的时候,根据链表中的指针情况,把链表中的指针进行了delete,这也就是等于把new出来的地址给delete掉了。
因为Add添加的是控件指针的索引,相当于引用,而不是复制操作,所以只需要delete掉链表中保存的指针即可完成内存的卸载,而不会造成内存的泄漏。
提供VS2010的例程下载地址在这里。
在项目开发时,可能遇到动态创建控件的情况。如根据当前用户的数量,动态创建控件显示用户信息等情况,需要动态常见静态文本框和编辑框等。
此时,利用控件类中Create()函数进行动态创建,默认是显示状态。如:
头文件定义:CStatic *p_MyStatic;
CPP中实现:
p_MyStatic = new CStatic();
p_MyStatic->Create("静态文本框",WS_CHILD|WS_VISIBLE|SS_CENTER,CRect(0,i*perHeight+5,perWidth,(i+1)*perHeight+5),this);
在退出时:
if(pStatic!=NULL)
delete pStatic;
对于单个或者固定数量的控件可以使用指针数组CStatic *p_MyStatic[TOTALCOUTS]照此进行。
但当TOTALCOUTS不固定时,可以使用MFC中CPtrArray进行开发,CPtrArray是一个链表类,用于保存动态创建的控件地址。
实现如下图所示的界面。
下面附上具体的代码:
- // DynamicMultiCtrlsDlg.h : 头文件
- #define EDIT_ID 10000
- public:
- CPtrArray p_MyStatics;
- CPtrArray p_MyEdits;
在点击创建时的具体执行代码如下:
- void CDynamicMultiCtrlsDlg::OnBnClickedBtnCreate()
- {
- // TODO: 在此添加控件通知处理程序代码
- CString m_staticCaption;
- CRect rect,rect2;
- GetClientRect(&rect);
- GetDlgItem(IDOK)->GetWindowRect(&rect2);
- ScreenToClient(&rect2);
- int m_counts =21;
- int perWidth = rect.Width()/4;
- int perHeight =rect2.top/m_counts;
- CStatic *p_MyStatic;
- CEdit *p_MyEdit;
- for(int i=0;i<m_counts;i++)
- {
- p_MyStatic = new CStatic();
- p_MyEdit = new CEdit();
- m_staticCaption.Format("第%d台IP地址:",i+1);
- if(i%2==0)
- {
- p_MyStatic->Create(m_staticCaption,WS_CHILD|WS_VISIBLE|SS_CENTER,CRect(0,i*perHeight+5,perWidth,(i+1)*perHeight+5),this);
- m_staticCaption.Format("%d台IP",i+1);
- p_MyEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER,CRect(perWidth,i*perHeight+5,perWidth*2,(i+1)*perHeight+5),this,EDIT_ID+i);
- p_MyEdit->SetWindowText(m_staticCaption);
- if(p_MyStatic!=NULL)
- {
- p_MyStatics.Add((void*)p_MyStatic);
- // delete p_MyStatic;
- }
- if(p_MyEdit!=NULL)
- {
- p_MyEdits.Add((void*)p_MyEdit);
- // delete p_MyEdit;
- }
- }else
- {
- p_MyStatic->Create(m_staticCaption,WS_CHILD|WS_VISIBLE|SS_CENTER,CRect(perWidth*2,(i-1)*perHeight+5,perWidth*3,i*perHeight+5),this);
- m_staticCaption.Format("%d台IP",i+1);
- p_MyEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER,CRect(perWidth*3,(i-1)*perHeight+5,perWidth*4,i*perHeight+5),this,EDIT_ID+i);
- p_MyEdit->SetWindowText(m_staticCaption);
- if(p_MyStatic!=NULL)
- {
- p_MyStatics.Add((void*)p_MyStatic);
- //delete p_MyStatic;
- }
- if(p_MyEdit!=NULL)
- {
- p_MyEdits.Add((void*)p_MyEdit);
- // delete p_MyEdit;
- }
- }
- }
- }
- 在有new的时候记得在程序退出时,delete掉所有new的指针
- void CDynamicMultiCtrlsDlg::OnClose()
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- int n=p_MyStatics.GetSize();
- for(int i=0;i<n;i++)
- {
- CStatic* pStatic=(CStatic*)p_MyStatics.GetAt(i);
- // pStatic->DestroyWindow();
- if(pStatic!=NULL)
- delete pStatic;
- p_MyStatics[i]=NULL;
- }
- p_MyStatics.RemoveAll();
- n=p_MyEdits.GetSize();
- for(int i=0;i<n;i++)
- {
- CEdit* pEdit=(CEdit*)p_MyEdits.GetAt(i);
- //pEdit->DestroyWindow();
- if(pEdit!=NULL)
- delete pEdit;
- p_MyEdits[i]=NULL;
- }
- p_MyEdits.RemoveAll();
- CDialogEx::OnClose();
- }
如在1和2的地方,我用了new,所以在总是在3和4的地方要把它们统统delete掉。可是这样导致了创建的控件无法显示。
为什么呢?
因为我把new出来的控件指针delete掉了,能显示出来才奇怪。
但是,不delete掉不会造成内存泄漏吗?
这个我在论坛发帖求助的时候,突然有个这样的理解:new出来的控件地址,已经全部保存到了CPtrArray链表中,而且在程序Close的时候,根据链表中的指针情况,把链表中的指针进行了delete,这也就是等于把new出来的地址给delete掉了。
因为Add添加的是控件指针的索引,相当于引用,而不是复制操作,所以只需要delete掉链表中保存的指针即可完成内存的卸载,而不会造成内存的泄漏。
提供VS2010的例程下载地址在这里。