2.5 组合框控件典型实例

组合框控件是编辑框控件和列表框控件的组合控件,它不仅可以提供用户选择的功能,也能提供用户输入的功能。本节通过几个实例介绍组合框控件的使用。

实例053 据表中的字段添加到组合框控件带将数据表中的字段添加到组合框控件

本实例可以方便操作、提高效率

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

实例说明

图2.14 将数据表中的字段添加到组合框控件

本实例实现将数据库中的数据添加到组合框控件中。运行程序,程序将Access数据库mrsoft.mdb中的数据添加到组合框控件中,数据表中单个字段的每一行对应组合框控件的一项,实例运行结果如图2.14所示。

技术要点

本实例主要通过ADO技术连接数据库,然后通过组合框控件的AddString方法添加从数据库读出的数据。AddString方法的语法如下:

int AddString( LPCTSTR lpszString );

参数说明:

● lpszString:要插入到组合框的字符串。

实现过程

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

(2)在对话框上添加组合框控件,设置ID属性为IDC_COMBO1,添加成员变量m_combo1。

(3)在StdAfx.h文件中导入ADO动态链接库,代码如下:

#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF" ,"adoEOF")

(4)主要程序代码如下:

            BOOL CComboBoxDlg::OnInitDialog()
            {
            CDialog::OnInitDialog();
            …//此处代码省略
            ::CoInitialize(NULL);                                         //初始化COM环境
            m_pConnection=NULL;
            m_pConnection.CreateInstance(__uuidof(Connection));           //连接对象实例化
            m_pConnection->ConnectionString="uid=admin;pwd=111;DRIVER=\
                  {Microsoft Access Driver(*.mdb)};DBQ=mrsoft.mdb;";        //设置连接字符串
            m_pConnection->Open(L"",L"",L"",adCmdUnspecified);            //打开数据库
            m_pRecordset=m_pConnection->Execute((_bstr_t)("select * from info"),
                  NULL,adCmdText);                                        //执行SQL语句
            while(!m_pRecordset->adoEOF)
            {
                  TheValue=(char*)(_bstr_t)m_pRecordset->GetCollect("name");//获得数据库中数据
                  m_combo1.AddString(TheValue);                           //插入到组合框中
                  m_pRecordset->MoveNext();                    //向下移动记录集指针
            }
            m_pRecordset->Close();
            m_pConnection->Close();
            m_pRecordset=NULL;
            m_pConnection=NULL;
            ::CoUninitialize();
            return TRUE;
            }

举一反三

根据本实例,读者可以:

将INI文件的数据加入到组合框控件;

将注册表中存储的数据加入到组合框控件。

实例054 带查询功能的组合框控件

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

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

实例说明

带查询功能的组合框控件主要是指,当用户在组合框控件中输入字符时,如果在组合框控件中有以该字符开头的字符串,组合框控件就将该字符串完全显示出来。本实例就是完成这样的功能,运行程序,在组合框控件中添加了英文的星期一到星期日字符串,如果用户输入字符“F”,字符串“Friday”将完全显示出来。程序运行结果如图2.15所示。

图2.15 带查询功能的ComboBox控件

技术要点

本实例主要通过CComboBox类的SelectString方法实现在组合框控件中查找符合要求的字符串,如果找到符合要求的字符串就将其返回。它的语法如下:

int SelectString( int nStartAfter, LPCTSTR lpszString );

参数说明:

● nStartAfter:指定开始查找的位置索引,如果为-1,从头开始查找。

● lpszString:所要查找的字符串。

通过CComboBox类的SetEditSel方法使字符串处于选中状态,语法如下:

BOOL SetEditSel( int nStartChar, int nEndChar );

参数说明:

● nStartChar:开始标识的位置索引。

● nEndChar:结束标识的位置索引。

实现过程

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

(2)在工程中添加新类AutoComplete。

(3)在对话框上添加组合框控件,添加成员变量m_sercmb,继承自新类AutoComplete。

(4)在对话框初始化时向组合框中插入数据,代码如下:

        BOOL CQueryComboBoxDlg::OnInitDialog()
        {
          CDialog::OnInitDialog();
          //…此处代码省略
          //向组合框中插入数据
          m_sercmb.AddString("Monday");
          m_sercmb.AddString("Tuesday");
          m_sercmb.AddString("Wednesday");
          m_sercmb.AddString("Thurday");
          m_sercmb.AddString("Friday");
          m_sercmb.AddString("Saturday");
          m_sercmb.AddString("Sunday");
            return TRUE;
        }

(5)在新类AutoComplete中添加CBN_EDITUPDATE消息的实现函数,代码如下:

        void AutoComplete::OnEditupdate()
        {
          if(!m_bAutoComplete)return;
          CString str;
          GetWindowText(str);                     //获得组合框的编辑框中文本
          int nLength=str.GetLength();             //获得文本长度
          DWORD dwCurSel=GetEditSel();             //获得文本的起始位置
          DWORD dStart =LOWORD(dwCurSel);
          DWORD dEnd =HIWORD(dwCurSel);
          if(SelectString(-1,str)==CB_ERR)        //查找字符
          {
            SetWindowText(str);                   //设置显示字符串
            if(dwCurSel!=CB_ERR)
            SetEditSel(dStart,dEnd);              //设置编辑框部分选中的字符串
          }
          GetWindowText(str);                     //获得组合框的编辑框中文本
          if(dEnd < nLength && dwCurSel!=CB_ERR)
            SetEditSel(dStart,dEnd);
          else
            SetEditSel(nLength,-1);
        }

(6)通过PreTranslateMessage处理组合框控件的WM_KEYDOWN消息,代码如下:

        BOOL AutoComplete::PreTranslateMessage(MSG* pMsg)
        {
          if(pMsg->message==WM_KEYDOWN)                 //如果键盘键按下
          {
            m_bAutoComplete=true;
            int nVirtKey=(int)pMsg->wParam;
            if(nVirtKey==VK_DELETE||nVirtKey==VK_BACK)  //按下的是删除键或返回键
            m_bAutoComplete=false;
          }
          return CComboBox::PreTranslateMessage(pMsg);
        }

举一反三

根据本实例,读者可以:

实现编辑框控件的自动查询功能。

实例055 自动调整组合框的宽度

这是一个可以提高分析能力的实例

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

实例说明

组合框控件的下拉列表宽度在默认情况下和组合框宽度是相同的,但是如果组合框中的字符串宽度超过了下拉列表的宽度,那么该字符串将不能完全显示。本实例通过自动调整组合框下拉列表的宽度来解决这一问题。运行程序,在组合框中添加宽度超出组合框宽度的字符串,单击组合框中的三角按钮,可以看到下拉列表已根据字符串的长度自动调整了宽度,如图2.16所示。

图2.16 自动调整组合框的宽度

技术要点

本实例主要通过处理OnCtlColor消息来实现,OnCtlColor消息主要用于处理控件的颜色,在处理该消息的函数中调用GetSystemMetrics函数来获得组合框控件的下拉列表宽度,然后通过CDC类的GetTextExtent方法获得字体的宽度。GetSystemMetrics函数用于获得各种窗体尺寸,语法如下:

int GetSystemMetrics(int nIndex);

参数说明:

● nIndex:想要获得系统配置的项目索引。主要取值如下。

■ SM_CXCURSOR:用户鼠标的x轴坐标。

■ SM_CYCURSOR:用户鼠标的y轴坐标。

■ SM_CXSCREEN:屏幕的宽度。

■ SM_CYSCREEN:屏幕的高度。

实现过程

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

(2)在工程中添加基于CcomboBox的新类MyComboBox。

(3)在对话框上添加组合框控件,设置ID属性为IDC_RESIZECMB,添加成员变量m_resizecmb,继承自新类MyComboBox。

(4)在新类MyComboBox中添加WM_CTLCOLOR消息的实现函数,代码如下:

            HBRUSH MyComboBox::OnCtlColor(CDC*pDC,CWnd*pWnd,UINT nCtlColor)
            {
            HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
            switch(nCtlColor)
            {
            case CTLCOLOR_EDIT:
            break;
            case CTLCOLOR_LISTBOX:
            int iItemNum=GetCount();                         //获得列表项数量
            int iWidth=0;
            CString strItem;
            CClientDC dc(this);
            int iSaveDC=dc.SaveDC();
            dc.SelectObject(GetFont());
            int iVSWidth=::GetSystemMetrics(SM_CXVSCROLL);   //获得下拉列表宽度
            for(int i=0;i<iItemNum;i++)
            {
          GetLBText(i,strItem);                           //获得选中的列表项文本
          int iWholeWidth=dc.GetTextExtent(strItem).cx+iVSWidth;//获得显示文本宽度
          iWidth=max(iWidth,iWholeWidth);                 //获得列表和文本中最大的宽度
        }
        iWidth+=dc.GetTextExtent("a").cx;
        dc.RestoreDC(iSaveDC);
        if(iWidth>0)
        {
          CRect rc;
          pWnd->GetWindowRect(&rc);                       //获得窗口区域
          if(rc.Width()!=iWidth)
          {
          rc.right=rc.left+iWidth;
          pWnd->MoveWindow(&rc);                          //设置窗口区域
          }
        }break;
        }
        return hbr;
        }

(5)在CComboBoxResizeDlg.cpp文件中向组合框中添加字符串数据,代码如下:

        BOOL CComboBoxResizeDlg::OnInitDialog()
        {
        CDialog::OnInitDialog();
        …//此处代码省略
        //向组合框中插入数据
        m_resizecmb.AddString("自动调整组合框宽度测试单元项目一");
        m_resizecmb.AddString("自动调整组合框宽度测试单元项目二");
        m_resizecmb.AddString("自动调整组合框宽度测试单元项目三");
        m_resizecmb.AddString("自动调整组合框宽度测试单元项目四");
        m_resizecmb.AddString("自动调整组合框宽度测试单元项目五");
        return TRUE;
        }

举一反三

根据本实例,读者可以:

根据字符串长度调整列表视图控件中单元格的宽度。

实例056 颜色组合框

这是一个可以提高分析能力的实例

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

实例说明

默认情况下,组合框只能显示文本信息,本实例是对组合框功能的扩展,实现在组合框中选择颜色。运行实例,单击组合框中的下三角按钮弹出列表,可以看到组合框中的每一项都由颜色矩形和颜色名称组成。实例运行结果如图2.17所示。

图2.17 颜色组合框

技术要点

为了能够在组合框中显示颜色,需要自定义一个组合框控件,改写DrawItem虚方法,在该方法中根据项目的当前状态,绘制相应效果的颜色和文本。为了获取当前项目的颜色值,笔者采用的方式是利用组合框中项目的附加信息来记录颜色值,即调用SetItemData方法为某个项目关联一个颜色值。然后利用GetItemData方法来获取该项目的颜色值。为了让用户在添加项目时能够设置项目的颜色值,程序中提供了一个AddItem,用于向组合框中添加一个颜色选项。

实现过程

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

(2)向对话框中添加组合框和图片控件。

(3)从CComboBox类派生一个子类CColorCombox,向该子类中添加AddItem方法,用于向颜色组合框中添加颜色选项。代码如下:

        int CColorCombox::AddItem(LPCTSTR lpszText, COLORREF clrValue)
        {
            int nIndex=AddString(lpszText);           //添加项目
            SetItemData(nIndex,clrValue);            //设置项目的颜色值
            return nIndex;                            //返回新添加的项目索引
        }

(4)向CColorCombox类中添加GetCurColor方法,获取当前选项的颜色值。代码如下:

        COLORREF CColorCombox::GetCurColor()
        {
            int nIndex = GetCurSel();
            if (nIndex != -1)
            {
                  return GetItemData(nIndex);
            }
            else
                  return -1;

(5)改写组合框类的DrawItem虚方法,根据当前项目的不同状态,来绘制相应效果的项目。代码如下:

            void CColorCombox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
            {
            ASSERT(lpDrawItemStruct->CtlType==ODT_COMBOBOX);                  //验证是否为组合框控件
            CDC dc ;
            dc.Attach(lpDrawItemStruct->hDC);
            CRect itemRC(lpDrawItemStruct->rcItem);                            //获取项目区域
            CRect clrRC=itemRC;                                                //定义显示颜色的区域
            CRect textRC=itemRC;                                               //定义文本区域
            COLORREF clrText=GetSysColor(COLOR_WINDOWTEXT);                    //获取系统文本颜色
            COLORREF clrSelected=GetSysColor(COLOR_HIGHLIGHT);                 //选中时的文本颜色
            COLORREF clrNormal=GetSysColor(COLOR_WINDOW);                      //获取窗口背景颜色
            int nIndex=lpDrawItemStruct->itemID;                               //获取当前项目索引
            int nState=lpDrawItemStruct->itemState;                            //判断项目状态
            if(nState&ODS_SELECTED)                                           //处于选中状态
            {
                  dc.SetTextColor((0x00FFFFFF& ~(clrText)));                 //文本颜色取反
                  dc.SetBkColor(clrSelected);                                 //设置文本背景颜色
                  dc.FillSolidRect(&clrRC,clrSelected);                       //填充项目区域为高亮效果
            }
            else
            {
                  dc.SetTextColor(clrText);                                   //设置正常的文本颜色
                  dc.SetBkColor(clrNormal);                                   //设置正常的文本背景颜色
                  dc.FillSolidRect(&clrRC, clrNormal);
            }
            if(nState&ODS_FOCUS)                                              //如果项目获取焦点,绘制焦点区域
            {
                  dc.DrawFocusRect(&itemRC);
            }
            int nclrWidth=itemRC.Width()/4;                                    //计算文本区域
            textRC.left = nclrWidth + 1;
            clrRC.DeflateRect(2,2);                                           //计算颜色显示区域
            clrRC.right = nclrWidth;
            //绘制颜色文本并且填充颜色区域
            if(nIndex!=-1)                                                    //项目不为空
            {
                  COLORREF clrItem=GetItemData(nIndex);                        //获取项目颜色
                  dc.SetBkMode(TRANSPARENT);
                  CString szText;
                  GetLBText(nIndex,szText);                                   //获取文本
                  //输出文本
                  dc.DrawText(szText, textRC, DT_LEFT|DT_VCENTER|DT_SINGLELINE);
                  dc.FillSolidRect(&clrRC,clrItem);                           //输出颜色
                dc.FrameRect(&clrRC,&CBrush(RGB(0,0,0)));               //绘制黑色边框
            }
            dc.Detach();
        }

(6)在主对话框中利用类向导为组合框控件命名为m_ColorBox,其类型为CColorCombox。

(7)在对话框初始化时向颜色组合框中添加颜色选项。代码如下:

        m_ColorBox.AddItem("红色", RGB(255, 0, 0));
        m_ColorBox.AddItem("蓝色", RGB(0, 0, 255));
        m_ColorBox.AddItem("绿色", RGB(0, 255, 0));
        m_ColorBox.AddItem("黄色", RGB(255, 255, 0));
        m_ColorBox.AddItem("粉色", RGB(255, 0, 255));
        m_ColorBox.AddItem("棕色", RGB(255, 128, 64));

举一反三

根据本实例,读者可以:

实现图标组合框。

实例057 多列显示的组合框

这是一个可以提高分析能力的实例

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

实例说明

组合框在默认情况下都是单列显示,单列显示的组合框只能提供单一的数据,如果是多列显示就可以提供一些提示信息或一些计算结果。本实例就是实现一个多列显示的组合框,运行程序,单击列表框中的下三角按钮,下拉列表变成3行3列的二维表格。程序运行结果如图2.18所示。

图2.18 多列显示的组合框

技术要点

本实例的实现需要覆写CComboBox类的DrawItem函数,新建基于CComboBox的新类MyComboBox,在MyComboBox类中添加函数DrawItem,DrawItem函数实现的是单行数据的绘制,在函数中通过LineTo方法来绘制直线,在两个单元格之间绘制直线,还需要绘制底部线条。

通过CStringList类来存储二维数据,通过CStringList对象的下标来代表行,通过CStringList类的AddHead方法来添加行的第一个数据,通过AddTail方法向行中追加数据项。

实现过程

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

(2)在工程中添加基于CComboBox的新类MyComboBox。

(3)在对话框上添加组合框控件,设置ID属性为IDC_MULCMB。

(4)在MyComboBox.h文件中添加变量声明:

        UINT totalcol;
        CStringList* ItemList;
        CString item[512];
        CStringList litem[5];

(5)自定义函数init完成组合框初始化,代码如下:

        void MyComboBox::init()
        {
        //插入列表项
        UINT itemindex;
        itemindex=CComboBox::AddString("row1");
        litem[0].AddHead("row1");
        litem[1].AddTail("1.00");
            litem[2].AddTail("11");
            itemindex=CComboBox::AddString("row2");
            litem[0].AddHead("row2");
            litem[1].AddTail("2.00");
            litem[2].AddTail("22");
            itemindex=CComboBox::AddString("row3");
            litem[0].AddHead("row3");
            litem[1].AddTail("3.00");
            litem[2].AddTail("3");
            this->SetCurSel(0);      //设置默认选中列表项
        }

(6)在新类MyComboBox中添加DrawItem函数,实现组合框自己绘制的功能,代码如下:

        void MyComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
        {
            CPen* pen;
            CDC*pDC=CDC::FromHandle(lpDrawItemStruct->hDC);                   //获得设备上下文
            CWnd*pListBox=pDC->GetWindow();                                   //获得窗口指针
            CRect rc1,rc2,rc3;
            CRect allrc=lpDrawItemStruct->rcItem;                              //获得区域
            BOOL select=lpDrawItemStruct->itemState&ODS_SELECTED;              //选中状态
            BOOL focus=lpDrawItemStruct->itemAction&ODA_FOCUS;                 //获得焦点
            BOOL textfocus=lpDrawItemStruct->itemState&ODS_FOCUS;
            COLORREF textcolor=GetSysColor(COLOR_WINDOWTEXT);
            COLORREF selectcolor=GetSysColor(COLOR_HIGHLIGHT);
            COLORREF normalcolor= GetSysColor( COLOR_WINDOW );
            int width=allrc.Width()/3;                                         //按提示窗口宽度分为3份
            rc1.SetRect(allrc.left,allrc.top,width,allrc.bottom);             //设置第1份区域
            rc2.SetRect(rc1.right,rc1.top,2*width,allrc.bottom);              //设置第2份区域
            rc3.SetRect(rc2.right,rc2.top,3*width,allrc.bottom);              //设置第3份区域
            if(select)
            {
            POSITION pos=litem[0].FindIndex(lpDrawItemStruct->itemID); //查找索引
            CString str1;str1=litem[0].GetAt(pos);                             //获得字符
            pDC->DrawText(str1,-1,rc1,DT_CENTER);                             //绘制字符
            }
            else
            {
            //绘制为选中的部分
            POSITION pos=litem[0].FindIndex(lpDrawItemStruct->itemID);
            CString str1;str1=litem[0].GetAt(pos);
            pDC->DrawText(str1,-1,rc1,DT_CENTER);
            pos=litem[1].FindIndex(lpDrawItemStruct->itemID);
            CString str2;str2=litem[1].GetAt(pos);
            pDC->DrawText(str2,-1,rc2,DT_CENTER);
            pos=litem[2].FindIndex(lpDrawItemStruct->itemID);
            CString str3;str3=litem[2].GetAt(pos);
            pDC->DrawText(str3,-1,rc3,DT_CENTER);
            //绘制分隔线
            pDC->MoveTo(allrc.left,allrc.bottom-1);
            pDC->LineTo(allrc.right,allrc.bottom-1);
            pDC->MoveTo(rc1.right,rc1.top);
            pDC->LineTo(rc1.right,allrc.bottom-1);
            pDC->MoveTo(rc2.right,rc2.top);
            pDC->LineTo(rc2.right,allrc.bottom-1);
            }
            if(focus)
            {
            pDC->DrawFocusRect(allrc); //绘制焦点框
            }
        }

(7)在新类MyComboBox中覆写AddString函数,调用自定义函数AddItem实现数据的添加,代码如下:

        int MyComboBox::AddString(LPCTSTR lpszString)
        {
            return AddItem(lpszString,0,CComboBox::GetCount());
        }

(8)添加自定义函数AddItem,该函数用于向组合框中添加数据,代码如下:

        int MyComboBox::AddItem(CString strItem,int nCol,int nRow,int nMask,int nFmt)
        {
          int item;
          if(nRow==CComboBox::GetCount())            //获得组合框中列表项行数
          item=CComboBox::AddString(strItem);        //向组合框中插入数据
          litem[nCol].AddTail(strItem);              //设置列项
          return 1;
        }

(9)在对话框初始化时实现组合框数据的初始化,代码如下:

        BOOL CMultiComboBoxDlg::OnInitDialog()
        {
        CDialog::OnInitDialog();
        …//此处代码省略
        m_mulcmb.init();
        return TRUE; }

举一反三

根据本实例,读者可以:

在编辑框控件中绘制多列表。

实例058 显示系统盘符组合框

这是一个可以提高分析能力的实例

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

实例说明

组合框在默认情况下都是用户自己添加数据,但是有些时候需要在不同的计算机中运行程序,那么,系统的盘符信息就是不固定的,为了解决这个问题,可以使用组合框的方法查找系统盘符,并显示出来。本实例就是实现显示系统盘符的组合框。程序运行结果如图2.19所示。

图2.19 显示系统盘符组合框

技术要点

本实例中使用了GetLogicalDriveStrings函数,该函数的作用是将系统中合法的盘符添加到字符缓冲区中。语法如下:

DWORD GetLogicalDriveStrings(DWORD nBufferLength, LPTSTR lpBuffer);

参数说明:

● nBufferLength:表示字符缓冲区的长度。

● lpBuffer:表示字符缓冲区。

返回值:如果函数执行成功,返回值是复制到缓冲区中的字节数,不包括终止符。如果函数执行失败,返回值为0。

实现过程

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

(2)在工程中添加一个扩展组合框控件,关联成员变量m_ComboEx。

(3)主要程序代码如下:

        void CComboCatalogDlg::LoadSysDisk()
        {
            m_ComboEx.SetImageList(&m_ImageList);
            m_ComboEx.ResetContent();
            char  pchDrives[128]={0};
            char* pchDrive;
            GetLogicalDriveStrings(sizeof(pchDrives),pchDrives); //列举盘符
            pchDrive = pchDrives;
            int nItem = 0;
            while(*pchDrive)
            {
                  COMBOBOXEXITEM       cbi;
                  CString          csText;
                  cbi.mask = CBEIF_IMAGE|CBEIF_INDENT|CBEIF_OVERLAY|
                              CBEIF_SELECTEDIMAGE|CBEIF_TEXT;
                  SHFILEINFO shInfo;                            //定义文件信息
                  int nIcon;
                  SHGetFileInfo(pchDrive, 0, &shInfo, sizeof(shInfo),
                    SHGFI_ICON|SHGFI_SMALLICON);               //获取系统文件图标
                  nIcon = shInfo.iIcon;
                  //设置COMBOBOXEXITEM结构
                  cbi.iItem            =nItem;
                  cbi.pszText          =pchDrive;
                  cbi.cchTextMax       =strlen(pchDrive);
                  cbi.iImage           =nIcon;
                  cbi.iSelectedImage   =nIcon;
                  cbi.iOverlay         =0;
                  cbi.iIndent          =(0&0x03);
                  m_ComboEx.InsertItem(&cbi);                  //插入数据
                  nItem++;
                  pchDrive += strlen(pchDrive) + 1;
            }
            }

举一反三

根据本实例,读者可以:

在组合框中显示查找的文件。