2.14 控件数组典型实例

在设计程序界面时,经常会在对话框中放置多个相同的控件,例如CStatic控件或CEdit控件。如果用户需要同时访问多个控件,例如清空所有编辑框中的文本,采用控件名称逐一进行清空未免有些麻烦。MFC应用程序完全支持控件数组,如果将相同类型的控件放置在控件数组中,那么通过遍历数组中的元素就可以访问每一个控件了。本节将通过几个实例介绍控件数组在应用程序开发中的应用。

实例086 向窗体中动态添加控件

这是一个可以提高基础技能的实例

实例位置:光盘\mingrisoft\02\086

实例说明

在使用标签控件CTabCtrl设计应用程序时,经常需要动态地创建控件,因为在设计期间,无法将其他控件直接放置在CTabCtrl控件上。本实例实现了动态向窗体中添加控件的功能,运行结果如图2.53所示。

图2.53 向窗体中动态添加控件

技术要点

动态创建控件可以分为3 个过程,首先定义一个控件对象,然后调用控件的Create方法创建控件窗口,最后调用ShowWindow方法显示窗口。例如,下面的代码动态创建了一个编辑框,代码如下:

            CEdit m_Edit;
            m_Edit.Create(WS_BORDER,CRect(10,10,50,30),this,0);    //创建编辑框控件
            m_Edit.ShowWindow(SW_SHOW);                            //显示控件

由于本实例需要动态创建多个控件,为了方便管理,采用控件数组动态创建控件。定义控件数组与定义普通的数组一样,只是数组类型是控件类型。例如:

            CStatic m_statics[6];
            CStatic m_static2[6];
            CEdit   m_edits1[6];
            CEdit   m_edits2[6];

当创建数组控件窗口时,利用循环就可以了,代码如下:

            for ( i = 0; i<6; i++)
            {
            pos = m_list1.FindIndex(i);
            if (pos != NULL)
            {
            //创建控件窗口
            m_spage1[i].Create(m_list1.GetAt(pos) , WS_CHILD,CRect(20,(i+1)*30+10,100,(i+1)*30+30),&m_tab);
            //显示控件
            m_spage1[i].ShowWindow(SW_SHOW);
            }
            m_epage1[i].Create(WS_BORDER,CRect(m_rect.left+100,m_rect.top+(i+1)*30+5,
              m_rect.left+250,m_rect.top+(i+1)*30+30),this,IDE_EDITCHANGE);
            m_epage1[i].ShowWindow(SW_SHOW);
          }

在动态创建控件时,有时还需要处理控件中的各种事件。例如,处理在编辑框文本改变时的事件实现某些功能,可以通过消息映射来处理控件中的各种事件。以编辑框的文本改变的事件为例,首先在对话框中定义一个事件处理函数,并在函数的声明处使用afx_msg关键字,标识该函数是消息处理函数。例如:

afx_msg void OnChangeEdit1();

然后在资源文件中定义一个资源ID,例如:

            #define IDE_EDITCHANGE                3201

最后在对话框的消息映射部分添加消息映射宏:

ON_EN_CHANGE(IDE_EDITCHANGE, OnChangeEdit1)

创建编辑框,将编辑框的ID指定为IDE_EDITCHANGE,这样在编辑框的文本发生改变时,会调用OnChangeEdit1消息处理函数。

实现过程

(1)新建一个基于对话框的应用程序。

(2)在对话框中添加CTabCtrl控件。

(3)在对话框类中添加如下成员变量:

        CStatic m_statics[6];            //标签1中的静态控件
        CStatic m_static2[6];            //标签2中的静态控件
        CEdit   m_edits1[6];            //标签1中的编辑框
        CEdit   m_edits2[6];            //标签2中的编辑框
        CStatic*  m_spage1,*m_spage2;
        CEdit*    m_epage1,*m_epage2;
        CStringList m_list1,m_list;      //记录静态控件文本

(4)在对话框类中添加CreateControl方法,创建控件,代码如下:

        void CDynamicCreateDlg::CreateControl()
        {
          CRect m_rect;
          m_tab.GetClientRect(m_rect);
          m_tab.MapWindowPoints(this,m_rect);
          POSITION pos=m_list1.GetTailPosition();
          int i;
          for(i=0;i<6;i++)
          {
          pos = m_list1.FindIndex(i);
          if (pos != NULL)
          {
          //创建控件窗口
          m_spage1[i].Create(m_list1.GetAt(pos) ,WS_CHILD,
            CRect(20,(i+1)*30+10,100,(i+1)*30+30),&m_tab);
            //显示控件
            m_spage1[i].ShowWindow(SW_SHOW);
          }
          m_epage1[i].Create(WS_BORDER,CRect(m_rect.left+100,m_rect.top+(i+1)*30+5,
                  m_rect.left+250,m_rect.top+(i+1)*30+30),this,IDE_EDITCHANGE); //创建控件
          m_epage1[i].ShowWindow(SW_SHOW);  //显示控件
          }
          for ( i = 0; i<6; i++)
          {
          pos = m_list.FindIndex(i);
          if (pos != NULL)
          {
                m_spage2[i].Create(m_list.GetAt(pos) , WS_CHILD,CRect(20,(i+1)*30+10,100,(i+1)*30+30),&m_tab);
          }
          m_epage2[i].Create(WS_BORDER,CRect(m_rect.left+100,m_rect.top+(i+1)*30+5,
                  m_rect.left+250,m_rect.top+(i+1)*30+30),this,4554);
          }
          }

举一反三

根据本实例,读者可以:

设计共享对话框基类。

实例087 公交线路模拟

这是一个可以提高基础技能的实例

实例位置:光盘\mingrisoft\02\087

实例说明

在开发有关地理定位的应用程序时,程序中经常需要描述各个地点的位置以及交通路线情况。为了清晰、准确地描述某个地点信息,通常采用图形和文字相结合的方式。本实例实现了一个公交线路的模拟程序,利用CStatic控件数组存储各个站点信息,实例运行结果如图2.54所示。

图2.54 公交线路模拟

技术要点

为了简化程序,本实例利用CStatic控件显示图像。在程序中定义一个CStatic类型的控件数组,在程序初始化时调用CStatic的Create方法创建窗口,并指定窗口显示的大小和位置,然后调用SetBitmap方法设置CStatic控件显示的图像。

下面主要介绍一下CStatic的Create方法和SetBitmap方法。

(1)Create方法。该方法用于创建窗口资源,语法如下:

BOOL Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );

参数说明:

● lpszText:用于指定控件显示的文本,本实例中,CStatic控件需要显示位图,所以该参数应该设置为空。

● dwStyle:指定控件风格,如果控件显示位图,该参数需要包含SS_BITMAP风格。

● rect:用于指定控件显示的区域。

● pParentWnd:标识控件的父窗口。

● nID:用于指定控件ID。

(2)SetBitmap方法。该方法用于显示位图信息,语法如下:

HBITMAP SetBitmap( HBITMAP hBitmap );

参数说明:

● hBitmap:绘制的位图句柄,通常可以利用LoadBitmap方法根据程序中导入的位图ID获取位图句柄。

● 返回值:是之前控件关联的位图句柄。如果控件之前没有关联位图,返回值为NULL。

实现过程

(1)新建一个基于对话框的应用程序。

(2)在对话框类中添加CStatic控件数组m_buses。

(3)在对话框类中添加DemoCircuitry方法,创建CStatic控件,并设置CStatic控件显示的位图,代码如下:

        void CRutineDemoDlg::DemoCircuitry()
        {
        m_buses[0].Create("",WS_CHILD|SS_BITMAP,CRect(40,80,100,140),this);
        m_buses[1].Create("",WS_CHILD|SS_BITMAP,CRect(180,180,240,240),this);
        m_buses[2].Create("",WS_CHILD|SS_BITMAP,CRect(350,140,400,380),this);
        m_buses[3].Create("",WS_CHILD|SS_BITMAP,CRect(460,220,500,400),this);
        m_buses[4].Create("",WS_CHILD|SS_BITMAP|WS_EX_TRANSPARENT,
        CRect(580,140,650,160),this);
        for (int i = 0;i<5;i++)
        {
          m_buses[i].SetBitmap(LoadBitmap(AfxGetInstanceHandle(),
        MAKEINTRESOURCE(IDB_BITMAP1)));
          m_buses[i].ShowWindow(SW_SHOW);
        }
        }

(4)利用属性对话框修改CStatic的属性,使其包含Simple风格。处理对话框的WM_CTLCOLOR消息,使CStatic控件背景透明,使对话框的背景呈白色,代码如下:

        HBRUSH CRutineDemoDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
        {
          HBRUSH hbr=CDialog::OnCtlColor(pDC,pWnd,nCtlColor);
        if (nCtlColor==CTLCOLOR_STATIC) //判断是否为CStaitc控件
          {
          pDC->SetBkMode(TRANSPARENT); //设置背景透明
          }
        else
          {
          CBrush m_brush(RGB(255,255,255)); //创建白色画刷
          CRect m_rect;
          GetClientRect(m_rect);            //获得客户区域
          pDC->SelectObject(&m_brush);      //选入画刷
          pDC->FillRect(m_rect,&m_brush);   //使对话框背景为白色
          return m_brush;
          }
        }

举一反三

根据本实例,读者可以:

设计旅游线路多媒体演示程序。