首页 > 代码库 > 通过编写串口助手工具学习MFC过程——(四)添加ComboBox组合框

通过编写串口助手工具学习MFC过程——(四)添加ComboBox组合框

通过编写串口助手工具学习MFC过程

因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉。这次通过做一个串口助手再次熟悉一下MFC,并做了一下记录,以便方便以后查阅。做的过程中多是遇到问题直接百度和谷歌搜索来的,所以很多都是不求甚解,知其然不知其所以然。另外做此工具只是为了熟悉了解,许多功能还没有完善!(开发工具VS2008)

(四)添加ComboBox组合框

ComboBox组合框有编辑框和下拉列表框的复合功能。通过该控件的Type属性可以进行相关设置。ComboBOX控件Type属性 :

Dropdown(默认)组合框,可下拉可编辑  

Drop List 下拉列表框,只能下拉不能编辑

Drop Simple  编辑框,只能编辑不能下拉。

属性:数据可设置下拉列表显示的内容,数据间隔用英文的分号”;”。下拉列表显示的内容也可以在程序中设置,如果这个下拉列表的内容可能会编辑更改,这里就不要设置,直接在程序在添加就可。

技术分享 技术分享

上图中属性Sort也很重要,将他设置成False就不会根据下拉列表的内容自动排列了,下拉列表显示的顺序就是自己想要的定义成的那样。

添加控件、修改属性ID和增加变量部分略,参见按按钮部分。

1、ComboBox的基本功能:

//校验位 无;奇校验;偶校验;

char verifiBuf[][7]={"无","奇校验","偶校验"};

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

{

m_ComboCheckBit.AddString(A2T(verifiBuf[i]));

}

m_ComboCheckBit.SetCurSel(0);

上面几行代码出现在初始对话框时,默认显示的。

m_ComboCheckBit.AddString(A2T(verifiBuf[i]));

在下拉列表增加字符串,不管原来是什么,直接增加到后面(Sort设置为False)。回值大于等于0时,是列表中项的下标。出错时,返回CB_ERROR,没有足够的空间存放新的字符串时返回CB_ERRSPACE。

A2T()将字符串转为宽字符WCHAR *。char verifiBuf[][7]定义成了二维数组来存储字符串,当然也可以定义成字符串数组来存储字符串。

m_ComboCheckBit.SetCurSel(0); 设置当前选项为第0项,如不设置,此组合框最初什么数值都没有。本函数在组合框的列表框中选择一个字符串,调用成功时返回选中的项的下标。如果nSelect大于列表中项的个数,则返回CB_ERR。如果nSelect为-1,则清除当前的选择并返回CB_ERR。

m_ComboCheckBit.GetCurSel();本函数用于取得组合框中当前选中的项的下标。返回组合框中列表框中当前选中的项的下标。如果没有选中项,则返回CB_ERR。

下面几行代码从组合框中获取字符串

//波特率

int baudIndex = pstComCWnds->pComboBaudActual->GetCurSel(); //波特率序号

pstComCWnds->pComboBaudActual->GetLBText(baudIndex,m_BaudStr); //从组合框的列表框中取得一个字符串(下标,获取字符串存入的cstring类)返回字符串长度

BaudRate = atoi(T2A((LPCTSTR)m_BaudStr)); //获得波特率

这个函数做为获得波特率在编辑自定义的波特率时要判断输入是否是数字,才能这么使用,否则不安全。

这个从组合框获取字符串的函数还有另一个重载。

int GetLBText( int nIndex, LPTSTR lpszText ) const;

返回字符串的字节数,不包括终结符null。如果nIndex指定的值无效,则返回CB_ERR。

(2)实现特殊功能:下拉列表自动调整宽度

串口名字是通过枚举获得的,名字较长,点下拉框时,名字不能完全显示。所以就让下拉框下拉时宽度变宽,从而能显示出完整的名字

当点击ComboBOX的三角使下拉列表展开时,下拉部分自动根据文字长度设置宽度,不改变原大小。

//ComboSelseri 选择串口组合框下拉动作响应将根据下拉选项最大的长度设定下拉框宽度

//控件添加 CbnDropdown 响应事件 下拉框下拉消息

void CserialtestDlg::OnCbnDropdownComboSelseri()

{

// TODO: 在此添加控件通知处理程序代码

int i = 0;

int originalLen = m_ComboSelSeri.GetDroppedWidth();  //获取原下拉框的宽度(像素)

int lenBuf = originalLen;

int lenTmp = 0;

//声明标识符

USES_CONVERSION; //使用A2T()或T2A()宽字节和多字节转换时使用的

//点开下拉框时,默认选择原来的那个串口

char m_SeriouStr[16] = {0};

CDeviceInfo * pCDeviceInfo = &m_DeviceInfo; //串口设备名字

int m_SeriouCurSel =  m_ComboSelSeri.GetCurSel();; //串口选择按钮,当前选择的序号

memcpy(m_SeriouStr, pCDeviceInfo->stDeviceInfo[m_SeriouCurSel].sDeviceName, sizeof(m_SeriouStr));//串口名字

m_ComboSelSeri.ResetContent(); //下拉列表清除列表项

for(i = 0; i<m_ComboSelSeri.GetCount();i++) //获取下拉列表项数

{

//获取下拉列表每项显示文字的字节数 并转为像素宽度。因为设置下拉列表的宽度单位是像素。此转换方式是用笨法测试出来的。

lenTmp = (m_ComboSelSeri.GetLBTextLen(i)+1)*CHAR_PIXEL_NUM;

if(lenTmp > lenBuf)

{

lenBuf = lenTmp;

}

}

if(lenBuf > originalLen)

m_ComboSelSeri.SetDroppedWidth(lenBuf);    //设置下拉列表的宽度(像素)

}

#define CHAR_PIXEL_NUM 6 //每个字符多少像素 人为根据现象设定

相关函数说明:

CComboBox::GetDroppedWidth
int GetDroppedWidth( ) const;
返回值:
调用成功时,返回允许的最小宽度,否则返回CB_ERR。
说明:
本函数用于取得组合框中的列表框所允许的最小宽度(以像素为单位)。它只对风格为CBS_DROPDOWN或CBS_DROPDOWNLIST的组合框有效。

CComboBox::SetDroppedWidth
int SetDroppedWidth( UINT nWidrh );
返回值:
调用成功时,返回列表框的新宽度。否则返回CB_ERR。
参数:nWidth 组合框的列表框所允许的最小宽度(以像素为单位)。

说明:
本函数用于设置组合框中列表框所允许的最小宽度。只对风格为CBS_DROPD-OWN或CBS_DROPDOWNLIST的组合框有效。

显示效果如下:

技术分享

(3)实现特殊功能:只能下拉和只能编辑切换属性

组合框只能下拉或只能做编辑功能好办,只需要修改控件的type属性为Drop List 或Drop Simple就能实现。但如果需要在程序运行过程中动态切换这两种属性如何做呢?

方法一:通过一个复选框实现切换功能

//复选框单击事件

void CserialtestDlg::OnBnClickedCheck1()

{

// TODO: 在此添加控件通知处理程序代码

long param ;

if(check1.GetCheck()) //获取复选框1(check1.)是否选中

{

//如果复选框1(check1.)被选中

check2.EnableWindow(FALSE); //另一个实验中  复选框禁止

//修改属性,CBS_DROPDOWN 原属性,CBS_DROPDOWNLIST新的属性

if(TRUE == m_comboBox1.ModifyStyle(CBS_DROPDOWN,CBS_DROPDOWNLIST))

{

printf("1111\n");

}

else

{

printf("2222\n");

}

//m_comboBox1.DestroyWindow();

RecreateComboBox(&m_comboBox1,&param); //修改属性实现,执行此功能才能修改控件属性。

}//m_LcConfig是你的ListCtrl控件变量

else

{

check2.EnableWindow(TRUE);

if(TRUE == m_comboBox1.ModifyStyle(CBS_DROPDOWNLIST,CBS_DROPDOWN))

{

printf("1111\n");

}

else

{

printf("2222\n");

}

//m_comboBox1.DestroyWindow();

RecreateComboBox(&m_comboBox1,&param);

}

}

复选框的功能将在下一节介绍,此函数中有printf()调试时打印语句,在VC的控制台程序中会打印输出,但MFC中默认不会打印输出,以后会介绍如何在MFC中添另控制台用于打印输出。

//RecreateComboBox函数引自://(http://www.codeproject.com/KB/combobox/recreatecombobox.aspx)

// recreate the combo box by copying styles etc, and list items

// and applying them to a newly created control

BOOL RecreateComboBox(CComboBox* pCombo, LPVOID lpParam/*=0*/)

{

if (pCombo == NULL)

return FALSE;

if (pCombo->GetSafeHwnd() == NULL)

return FALSE;

CWnd* pParent = pCombo->GetParent();

if (pParent == NULL)

return FALSE;

// get current attributes

DWORD dwStyle = pCombo->GetStyle();

DWORD dwStyleEx = pCombo->GetExStyle();

CRect rc;

pCombo->GetDroppedControlRect(&rc);

pParent->ScreenToClient(&rc); // map to client co-ords

UINT nID = pCombo->GetDlgCtrlID();

CFont* pFont = pCombo->GetFont();

CWnd* pWndAfter = pCombo->GetNextWindow(GW_HWNDPREV);

// get the currently selected text (and whether it is a valid list selection)

CString sCurText;

int nCurSel = pCombo->GetCurSel();

BOOL bItemSelValid = nCurSel != -1;

if (bItemSelValid)

pCombo->GetLBText(nCurSel, sCurText);

else

pCombo->GetWindowText(sCurText);

// copy the combo box items into a temp combobox (not sorted)

// along with each item‘s data

CComboBox comboNew;

if (! comboNew.CreateEx(dwStyleEx, _T("COMBOBOX"), _T(""),

dwStyle, rc, pParent, nID, lpParam))

return FALSE;

comboNew.SetFont(pFont);

int nNumItems = pCombo->GetCount();

for (int n = 0; n < nNumItems; n++)

{

CString sText;

pCombo->GetLBText(n, sText);

int nNewIndex = comboNew.AddString(sText);

comboNew.SetItemData(nNewIndex, pCombo->GetItemData(n));

}

// re-set selected text

if (bItemSelValid)

comboNew.SetCurSel(comboNew.FindStringExact(-1, sCurText));

else

comboNew.SetWindowText(sCurText);

// destroy the existing window, then attach the new one

pCombo->DestroyWindow();

HWND hwnd = comboNew.Detach();

pCombo->Attach(hwnd);

// position correctly in z-order

pCombo->SetWindowPos(pWndAfter == NULL ?

&CWnd::wndBottom :

pWndAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

return TRUE;

}

方法二:通过两个组合列表框交替使用来实现

本例中使用了下面的方法,此方法是自己原创(也许不是,只是自己按方法一实现后想到的另一种实现方法而已)

通过两个组合列表框交替使用来实现, 并将使用的赋给程序正常用时的指针变量。pComboBaudActual为程序中使用的指针变量,他保存两个组合列表框中的正在使用的那个地址。

并将正在使用的组合列表框显示,将不在使用的隐藏(这两个组合框位置上重合,程序执行起来就像是同一个组合框一样)。

把当前组合框选中的项,设定为新组合框的选项。通过pComboBaudActual指针实现。

//两个组合框添加  CBN_SELCHANGE事件响应, 控件中的选定内容已更改事件。

//ComboBaud 波特率组合框选中切换某一项动作

void CserialtestDlg::OnCbnSelchangeComboBaud()

{

// TODO: 在此添加控件通知处理程序代码

int i =0;

if((i = pComboBaudActual->GetCurSel()) == 0) //当列表框选择第0项时

{

//切换组合框

pComboBaudActual ->ShowWindow(SW_HIDE);  //原来使用的隐藏

pComboBaudActual = &m_ComboBaudEdit; //将另一个要使用赋值

pComboBaudActual ->SetCurSel(i); //并将选择项赋给新列表

pComboBaudActual->ShowWindow(SW_SHOW); //将新列表框显示

}

}

//ComboBaudedit 波特率组合框选中切换某一项动作

//这是另一个组合框选择程序,功能与上个函数相同

void CserialtestDlg::OnCbnSelchangeComboBaudedit()

{

// TODO: 在此添加控件通知处理程序代码

int i =0 ;

if((i = pComboBaudActual->GetCurSel()) != 0)

{

//切换组合框

pComboBaudActual ->ShowWindow(SW_HIDE);

pComboBaudActual = &m_ComboBaud;

pComboBaudActual ->SetCurSel(i);

pComboBaudActual->ShowWindow(SW_SHOW);

}

}

pComboBaudActual->ShowWindow(SW_SHOW); //将列表框显示

pComboBaudActual ->ShowWindow(SW_HIDE); //将列表框隐藏

通过编写串口助手工具学习MFC过程——(四)添加ComboBox组合框