在MFC中创建动态控件的生成与响应

2008-10-22 作者:风林 网友评论 1 条 点击进入论坛

  动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的。

  一、创建动态控件:

  为了对照,我们先来看一下静态控件的创建。

  放置静态控件时必须先建立一个容器,一般是对话框,这时我们在对话框编辑窗口中,从工具窗口中拖出所需控件放在对话框中即可,再适当修改控件ID,设置控件属性,一个静态控件就创建好了,当对话框被显示时,其上的控件也会显示。

  静态控件不需要调用Create()函数来创建。

  而创建动态控件有很大不同,以下以按钮为例,看一下动态控件的创建过程:

  1.建立控件ID号:

  ID号是控件的标识,创建控件前必须先为它设置一个ID号。

  打开资源中的“String Table”,在空白行上双击鼠标,这时会弹出一个ID属性对话框,在其中的ID编辑框中输入ID,如:IDC_MYBUTTON,在Caption中输入控件标题或注解(注:Caption框不能为空,为空会导致创建失败),这里我输入的是按钮上要显示的文字--动态按钮。

  2.建立控件对象:

  不同种类的控件应创建不同的类对象:

  按钮控件 CButton (包括普通按钮、单选按钮和复选按钮)

  编辑控件 CEdit

  静态文本控件 CStatic

  标签控件 CTabCtrl

  旋转控件 CSpinButtonCtrl

  滑标控件 CSliderCtrl

  多信息编辑控件 CRichEditCtrl

  进度条控件 CProgressCtrl

  滚动条控件 CSrcollBar

  组合框控件 CComboBox

  列表框控件 CListBox

  图像列表控件 CImageCtrl

  树状控件 CTreeCtrl

  动画控件 CAnimateCtrl

  本例中我们创建一个CButton类的普通按钮。注意不能直接定义CButton对象,如:CButton m_MyBut;这种定义只能用来给静态控件定义控制变量,不能用于动态控件。

  正确做法是用new调用CButton构造函数生成一个实例:

  CButton *p_MyBut = new CButton();

  然后用CButton类的Create()函数创建,该函数原型如下:

  BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

  lpszCaption是按钮上显示的文本;

  dwStyle指定按钮风格,可以是按钮风格与窗口风格的组合,取值有:

  窗口风格:

  WS_CHILD 子窗口,必须有

  WS_VISIBLE 窗口可见,一般都有

  WS_DISABLED 禁用窗口,创建初始状态为灰色不可用的按钮时使用

  WS_TABSTOP 可用Tab键选择

  WS_GROUP 成组,用于成组的单选按钮中的第一个按钮

  按钮风格:

  BS_PUSHBUTTON 下压式按钮,也即普通按钮

  BS_AUTORADIOBUTTON 含自动选中状态的单选按钮

  BS_RADIOBUTTON 单选按钮,不常用

  BS_AUTOCHECKBOX 含自动选中状态的复选按钮

  BS_CHECKBOX 复选按钮,不常用

  BS_AUTO3STATE 含自动选中状态的三态复选按钮

  BS_3STATE 三态复选按钮,不常用

  以上风格指定了创建的按钮类型,不能同时使用,但必须有其一。

  BS_BITMAP 按钮上将显示位图

  BS_DEFPUSHBUTTON 设置为默认按钮,只用于下压式按钮,一个对话框中只能指定一个默认按钮

  rect指定按钮的大小和位置;

  pParentWnd指示拥有按钮的父窗口,不能为NULL;

  nID指定与按钮关联的ID号,用上一步创建的ID号。

  不同控件类的Create()函数略有不同,可参考相关资料。

  例:p_MyBut->Create( "动态按钮", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(20,10,80,40), this, IDC_MYBUTTON );

  这样,我们就在当前对话框中的(20,10)处创建了宽60,高30,按钮文字为“动态按钮”的下压式按钮。

  为了使创建过程更方便易用,我定义了如下函数:

  CButton* CTextEditorView::NewMyButton(int nID,CRect rect,int nStyle)

  {

  CString m_Caption;

  m_Caption.LoadString( nID ); //取按钮标题

  CButton *p_Button = new CButton();

  ASSERT_VALID(p_Button);

  p_Button->Create( m_Caption, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | nStyle, rect, this, nID ); //创建按钮

  return p_Button;

  }

  其中m_Caption.LoadString( nID )是从字符串表中读取按钮文本,这样在创建按钮ID时,应该把文本设置好,参数nStyle为除必须风格外的额外风格。

  以下,我调用该函数创建三个按钮,并指定第一个按钮为默认按钮,按钮的ID已预先设置好了:

  CButton *p_MyBut[3];

  p_MyBut[0] = NewMyButton( ID_MYBUT1, CRect(10,20,50,35), BS_DEFPUSHBUTTON );

  p_MyBut[1] = NewMyButton( ID_MYBUT2, CRect(55,20,95,35), 0 );

  p_MyBut[2] = NewMyButton( ID_MYBUT3, CRect(100,20,140,35), 0 );

  二、动态控件的响应:

  动态控件的响应函数不能用ClassWizard添加,只能手动添加。仍以上面的按钮为例,我们制作按钮的单击响应函数。

  1.在MESSAGE_MAP中添加响应函数:

  MESSAGE_MAP表中定义了消息响应函数,其格式为:消息名(ID,函数名),当我们用ClassWizard添加函数时,会自动添加在AFX_MSG_MAP括起的区间内,如:

  BEGIN_MESSAGE_MAP(CTextEditorView, CFormView)

  //{{AFX_MSG_MAP(CTextEditorView)

  ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0)

  //}}AFX_MSG_MAP

  END_MESSAGE_MAP()

  手工添加时不要添加到AFX_MSG_MAP区间内,以防ClassWizard不能正常工作,如:

  BEGIN_MESSAGE_MAP(CTextEditorView, CFormView)

  //{{AFX_MSG_MAP(CTextEditorView)

  ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0)

  //}}AFX_MSG_MAP

  ON_BN_CLICKED(ID_MYBUT1, OnMybut1)

  ON_BN_CLICKED(ID_MYBUT2, OnMybut2)

  ON_BN_CLICKED(ID_MYBUT3, OnMybut3)

  END_MESSAGE_MAP()

  其中ON_BN_CLICKED是按钮单击消息。

  2.在头文件中添加函数定义:

  用ClassWizard添加函数时,会在头文件的AFX_MSG区间内添加函数定义,如:

  protected:

  //{{AFX_MSG(CTextEditorView)

  afx_msg void OnIconbut0();

  //}}AFX_MSG

  DECLARE_MESSAGE_MAP()

  我们模仿这种形式,只是把函数定义添加到AFX_MSG区间外就行了:

  protected:

  //{{AFX_MSG(CTextEditorView)

  afx_msg void OnIconbut0();

  //}}AFX_MSG

  afx_msg void OnMybut1();

  afx_msg void OnMybut2();

  afx_msg void OnMybut3();

  DECLARE_MESSAGE_MAP()

  3.编写消息响应函数:

  以上是把消息和函数关联起来了,具体在单击按钮后应做的工作在函数中完成:

  void CTextEditorView::OnMybut1()

  {

  MessageBox( "哈!你单击了动态按钮。" );

  }

  void CTextEditorView::OnMybut2()

  {

  ……

  }

  void CTextEditorView::OnMybut3()

  {

  ……

  }

  除了按钮的响应函数外,你还可以用上面获得的指针访问按钮,如:

  修改按钮的大小和位置:p_MyBut[0]->MoveWindow(……);

  修改按钮文本:p_MyBut[0]->SetWindowText(……);

  显示/隐藏按钮:p_MyBut[0]->ShowWindow(……);等等。

  三、回收资源:

  由于动态控件对象是由new生成的,它不会被程序自动释放,所以需手工释放。在控件不再使用时可以删除它:

  if( p_MyBut[0] )

  delete p_MyBut[0];

  以上就是按钮控件动态生成的方法。下面,再看一下单选按钮的动态生成问题。

  四、实例:单选按钮组的动态生成

  单选按钮也属于CButton类,但由于单选按钮总是成组使用的,所以它在制作和使用上与普通按钮有一定区别。

  假设有三个单选按钮组成一组,初始时,第一个单选按钮处于选中状态。

  我们先来看静态制作方法:在对话框中放置三个单选按钮,设置属性如下:

  Radio1属性:Visible、Group、Tab stop、Auto

  Radio2属性:Visible、Tab stop、Auto

  Radio3属性:Visible、Tab stop、Auto

  这样的属性设置就把三个单选按钮分成了一组,它们一次只能有一个被选中,若对话框中还有其它成组的单选按钮,使用时也会互不干扰。但这时还没有使第一个按钮处于选中状态。

  接着就用ClassWizard为这组单选按钮添加变量,这里只需为第一个单选按钮添加变量即可。设变量名为m_Radio,类型选为int型。在构造函数中ClassWizard把m_Radio的值设置为-1,我们把它改为0,这样在运行程序时可以看到第一个单选按钮处于选中状态了。

  之后,还应该用ClassWizard为三个单选按钮添加单击响应函数,在里面修改m_Radio的值对应三个单选按钮就可以了。

  以上就是通常制作单选按钮组的办法,现我们欲改为动态生成,主要要解决按钮分组和单击控制问题。以下为制作步骤:

  1.定义三个单选按钮的ID:

  打开资源中的“String Table”,在其中添加三个ID值:

  第一个:ID为IDC_MYRADIO1,Caption为单选1

  第二个:ID为IDC_MYRADIO2,Caption为单选2

  第三个:ID为IDC_MYRADIO3,Caption为单选3

  其中Caption为按钮上要显示的文字,可根据需要设置。

  2.用CButton类的Create()函数生成三个单选按钮:

  为方便起见,先定义一个函数生成单选按钮:

  CButton* CTextEditorView::NewMyRadio(int nID,CRect rect,int nStyle)

  {

  CString m_Caption;

  m_Caption.LoadString( nID ); //取按钮标题

  CButton *p_Radio = new CButton();

  ASSERT_VALID(p_Radio);

  p_Radio->Create( m_Caption, WS_CHILD | WS_VISIBLE | nStyle | WS_TABSTOP | BS_AUTORADIOBUTTON, rect, this, nID ); //创建按钮

  return p_Radio;

  }

  函数LoadString()用于从“String Table”中读取按钮文本,Create()函数中设定了单选按钮必须的属性,其中就包括了Visible、Tab stop、Auto属性。

  参数nID为单选按钮ID号,rect为单选按钮尺寸,nStyle为除必要属性外的其它属性。返回值为指向新建按钮的指针。

  有了这个函数后,创建单选按钮组时只要依次调用该函数即可,其中单选按钮组的第一个单选按钮必须指定WS_GROUP属性。

  CButton *p_MyRadio[3];

  p_MyRadio[0] = NewMyRadio( IDC_MYRADIO1, CRect(15,90,60,105), WS_GROUP );

  p_MyRadio[1] = NewMyRadio( IDC_MYRADIO2, CRect(15,108,60,123), 0 );

  p_MyRadio[2] = NewMyRadio( IDC_MYRADIO3, CRect(15,126,60,141), 0 );

  3.定义单选按钮组的控制变量,设置第一个单选按钮为选中状态:

  这里不能用ClassWizard添加变量,也不要在DoDataExchange()中添加控制变量,因为动态控件一开始并不存在,在DoDataExchange()中添加控制变量会造成运行错误。这里我们只需在头文件中随意定义一个int型变量作为控制变量即可,如:

  int m_SelRadio;

  在构造函数中设置其初值为0:m_SelRadio = 0;

  在上面的创建按钮的语句中,用SetCheck()函数设置初始选中的按钮:

  CButton *p_MyRadio[3];

  p_MyRadio[0] = NewMyRadio( IDC_MYRADIO1, CRect(15,90,60,105), WS_GROUP );

  p_MyRadio[1] = NewMyRadio( IDC_MYRADIO2, CRect(15,108,60,123), 0 );

  p_MyRadio[2] = NewMyRadio( IDC_MYRADIO3, CRect(15,126,60,141), 0 );

  p_MyRadio[m_SelRadio]->SetCheck(1); //设置第一个单选为选中状态

  在SetCheck()函数中,参数为1表示设置为选中状态,为0表示未选中状态。

  4.添加鼠标单击响应函数:

  鼠标单击某单选按钮后,其状态已经能自动改变,这里我们还需修改控制变量m_SelRadio的值,以便跟踪选中的单选按钮。

  首先在MESSAGE_MAP中把鼠标单击消息与响应函数联系起来:

  BEGIN_MESSAGE_MAP(CTextEditorView, CFormView)

  //{{AFX_MSG_MAP(CTextEditorView)

  ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0) //ClassWizard在此处添加

  //}}AFX_MSG_MAP

  ON_BN_CLICKED(IDC_MYRADIO1, OnMyRadio1) //单选按钮1

  ON_BN_CLICKED(IDC_MYRADIO2, OnMyRadio2) //单选按钮2

  ON_BN_CLICKED(IDC_MYRADIO3, OnMyRadio3) //单选按钮3

  END_MESSAGE_MAP()

  然后在头文件的MESSAGE_MAP中定义单击函数:

  protected:

  //{{AFX_MSG(CTextEditorView)

  afx_msg void OnIconbut0(); //ClassWizard在此处添加

  //}}AFX_MSG

  afx_msg void OnMyRadio1(); //单选按钮1

  afx_msg void OnMyRadio2(); //单选按钮2

  afx_msg void OnMyRadio3(); //单选按钮3

  DECLARE_MESSAGE_MAP()

  这里注意不要把函数加在AFX_MSG区间内,以防影响ClassWizard的使用。

  定义具体的响应函数(这里是用手工加入的,不是用ClassWizard加入的):

  //单击单选按钮1 void CTextEditorView::OnMyRadio1()

  {

  m_SelRadio=0;

  }

  //单击单选按钮2 void CTextEditorView::OnMyRadio2()

  {

  m_SelRadio=1;

  }

  //单击单选按钮3 void CTextEditorView::OnMyRadio3()

  {

  m_SelRadio=2;

  }

  5.回收资源:

  在析构函数中,回收创建的单选按钮(也可以在不使用单选按钮时立即回收):

  CTextEditorView::~CTextEditorView()

  {

  int i;

  for( i=0; i<3; i++)

  {

  if(p_MyRadio[i])

  delete p_MyRadio[i];

  }

  }

  以上就是动态控件的生成和响应方法,各种不同的控件做法略有不同,但思路和步骤都是类似的,希望以上实例对你能够有所帮助。

在MFC中创建动态控件的生成与响应相关推荐

  1. 转:MFC中创建多线程

    MFC中创建多线程 MFC的多线程函数必须声明为静态的或者是全局函数(不同的在于全局函数不能访问类的私有静态成员,而静态类函数可以):但这样的线程函数只能访问静态的成员变量,要实现访问类的其他成员,可 ...

  2. MFC中创建和使用线程的方法

    有关创建线程的问题有三种方法: 1.C语言函数,调用_beginthread(); 2.API函数,调用CreateThread(); 3.MFC函数,调用AfxBeginThread(); 推荐使用 ...

  3. MFC中创建线程实例

    static UINT ThreadFunc(LPVOID pParam); //线程函数声明UINT CTestApp::ThreadFunc(LPVOID pParam)//可以传递对话框的等指针 ...

  4. java response excel_java-返回在servlet中创建的excel文件作为响应

    我已经使用Apache POI创建了excel文件,并尝试将其返回为对ajax调用的响应.我希望浏览器提示"保存创建的文件"窗口. 问题是我在servlet的响应中出现混乱,没有任 ...

  5. MFC中动态创建控件以及事件响应实现方法

    本文实例讲述了MFC中动态创建控件以及事件响应实现方法,分享给大家供大家参考.具体实现方法如下: 动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的. 一.创建动态 ...

  6. MFC中动态创建控件以及添加事件响应

    本文实例讲述了MFC中动态创建控件以及事件响应实现方法,分享给大家供大家参考.具体实现方法如下: 动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的. 一.创建动态 ...

  7. 【MFC】对话框中创建工具栏

    00. 目录 文章目录 00. 目录 01. 案例概述 02. 开发环境 03. 关键技术 04. 程序设计 05. 秘笈心法 06. 源码下载 07. 附录 01. 案例概述 使用MFC向导可以创建 ...

  8. MFC中动态创建控件及添加消息响应的方法实例

    动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的. 一.创建动态控件: 为了对照,我们先来看一下静态控件的创建. 放置静态控件时必须先建立一个容器,一般是对话框, ...

  9. asp.net mysql 创建变_[ASP.net教程]EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型...

    [ASP.net教程]EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型 0 2018-06-30 07:00:08 官方教程: ...

最新文章

  1. OpenAI 发布通用人工智能研究纲领:以全人类的名义承诺
  2. linux命令怎么打开优盘,Linux下U盘使用具体步骤
  3. linux 中ans 用法,JSON简介以及用法汇总
  4. MySQL常用数据类型小结
  5. 设置storage模块的数据库操作支持、添加仓储分类列表接口(dao层)
  6. Django 静态文件处理
  7. Cookie使用基础
  8. XenCenter导出和导入模板
  9. Ae效果控件快速参考:3D 通道
  10. python爬取网易云评论 超简单教程
  11. win10系统怎么查看密钥?
  12. 如何做自己不想做的事情,却必须要去做的事情
  13. 有机化学反应里php什么意思,有机反应类型解读
  14. Flowable工作流引擎技术方案
  15. APP元素定位工具Weditor连接夜神模拟器
  16. 手把手教你创建群晖nas「共享文件夹」,从此告别 U 盘和低效传输
  17. 人工智能的应用实例介绍,人工智能有哪些应用领域?
  18. 2022考研笔记-政治大纲
  19. Samba+Vsftpd+Mysql搭建平台实验
  20. Python Flask 构建微电影视频网站

热门文章

  1. python中dir用法_Python内置函数dir详解
  2. (JAVA学习笔记) 关于稀疏数组
  3. Android从普通发送和接收短信到对短信进行拦截
  4. C语言实例第5期:在控制台打印100-200之间的所有素数
  5. 宇视智能锁门禁服务器,宇视T1P系列智能锁
  6. java jvm调优面试题_【Java面试题第一期】有没有jvm调优经验?调优方案有哪些?...
  7. 超实用的网络故障排障指南
  8. 【必看】这6个吓人的Linux命令,你用过吗?
  9. 【必看】如何向女朋友解释TCP的三次握手和四次挥手
  10. 小半计算机谱子,小半 _桃李醉春风个人制谱园地_中国曲谱网