由于课题的需求需要做MFC串口程序,看了百度下载的串口助手的界面风格,发现这个设计很好

波特率的组合框只给出了5个可选数值,然后第6个选项是Custom,即手动输入。

实际上DCB结构的BaudRate可选数值太多了,做成下拉框会很长很长,这种做法就是选用最常见的几个选项,不需要用户手动输入,也不需要在很长的列表中去选择。

从VS的属性框中可以看到,组合框控件有3种样式,也就是实现的功能是点击Custom选项时从Drop List切换到Dropdown。

从MSDN可以看到两者对应的宏分别为CBS_DROPDOWNLIST和CBS_DROPDOWN。

参考:https://msdn.microsoft.com/en-us/library/12h9x0ch.aspx

所以我最初在想用CWnd::Modify()方法来修改样式,但是失败了,搜寻的原因时,下拉样式只能在创建的时候确定,创建之后就无法更改了。

因此合理的做法是手动Create一个一模一样的控件,然后用CWnd::ShowWindow()方法来自动切换。

-----------------------------------------------------------------------------------分割线----------------------------------------------------------------------------------

下面给出从0开始详尽的实现方法,新建一个基于MFC对话框程序(设对话框类为CComboTestDlg),手动拖一个ComboBox控件上去。设置Type和ID

在类向导里给该控件添加CComboBox类型的关联变量,或者像下面一样手动添加:

1. 在ComboTestDlg.h中,CXXXDlg类中定义public变量

CComboBox m_cmbOld;

2. 在ComboTestDlg.cpp中,CXXXDlg::DoDataExchange()方法中添加一行关联语句

DDX_Control(pDX, IDC_COMBO_OLD, m_cmbOld);

现在在CComboTestDlg类中定义public变量m_cmbNew,但是不要修改DoDataExchange()方法,因为等下要手动创建下拉框

CComboBox m_cmbNew;

修改CComboTestDlg::OnInitDialog()方法,添加下述代码

    // 获取原来的下拉框的位置
CRect rect;
m_cmbOld.GetWindowRect(&rect);
this->ScreenToClient(&rect);
// 获取原来的下拉框的字体
CFont* pFont = m_cmbOld.GetFont();
// 获取原来的下拉框的样式(把Drop list改成Dropdown)
DWORD dwStyle = m_cmbOld.GetStyle();
dwStyle ^= CBS_DROPDOWNLIST;
dwStyle |= CBS_DROPDOWN;
// 创建一模一样的新下拉框
m_cmbNew.Create(dwStyle, rect, this, IDC_COMBO_NEW);
// 设置相同的字体
m_cmbNew.SetFont(pFont);
// 默认隐藏新下拉框
m_cmbNew.ShowWindow(SW_HIDE);

上述代码里有两点要注意(也就是我踩过的坑……)

1. 坐标转换ScreenToClient,因为GetWindowRect取得的是相对整个父控件(包含标题栏)的位置,而Create需要的是相对客户区(不包括标题栏)的位置,所以需要转换;

2. GetFont和SetFont设置字体,没有这一步的话,Create创建的下拉框的字体可能会和自动创建的下拉框字体不一样。

PS:宏IDC_COMBO_NEW需要手动在resource.h中添加,注意不要和其他的宏相同,以免冲突。

到此为止就只需要实现切换功能了,假设我的下拉框包含4项:cpp, java, python, custom,点击custom则切换到手动输入模式。

在ComboTestDlg.cpp中添加全局变量(列表初始化是C++11的语法)以便之后直接通过下标访问

#include <vector>

std::vector<CString> g_strText = { _T("cpp"), _T("java"), _T("python"), _T("custom") };

在CComboTestDlg::OnInitDialog()中刚才添加的代码后面继续添加初始化代码

for (size_t i = ; i < g_strText.size(); i++)
{ // C++11中可以用<type_traits>的std::extent<decltype(text)>::value取得text数组大小
m_cmbOld.AddString(g_strText[i]);
m_cmbNew.AddString(g_strText[i]);
}
m_cmbOld.SetCurSel(); // 默认选择第一项("cpp")

然后分别给2个控件添加响应事件,对于默认控件m_cmbOld,可以用类向导添加相应方法

实际上做了这几件事:

1. 在ComboTestDlg.h中,在CComboTestDlg类中添加成员函数的声明

afx_msg void OnCbnSelchangeComboOld();

2. 在ComboTestDlg.cpp中,在消息映射宏BEGIN_MESSAGE_MAP(CComboTestDlg, CDialog)和END_MESSAGE_MAP()之间添加

ON_CBN_SELCHANGE(IDC_COMBO_OLD, &CComboTestDlg::OnCbnSelchangeComboOld)

3. 在CComboTestDlg.cpp中,添加成员函数的具体定义

void CComboTestDlg::OnCbnSelchangeComboOld()
{
// TODO: 在此添加控件通知处理程序代码
}

知道了这几点后,照葫芦画瓢,在上述3步同样的位置添加相应的代码,如果选择已有项,则会显示原来的下拉框。

afx_msg void OnCbnSelChangeComboNew();
ON_CBN_SELCHANGE(IDC_COMBO_NEW, &CComboTestDlg::OnCbnSelChangeComboNew)
void CComboTestDlg::OnCbnSelChangeComboNew()
{ }

而输入自定义数据时,则需要响应回车消息,用类向导(如下图,点击添加函数)给CComboTestDlg重载虚函数PreTranslateMessage()

这一步实际做了这几件事:

1. 在ComboTestDlg.h中,在CComboTestDlg类中添加虚函数的声明

virtual BOOL PreTranslateMessage(MSG* pMsg);

2. 在ComboTestDlg.cpp中,添加虚函数的定义

BOOL CComboTestDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类 return CDialog::PreTranslateMessage(pMsg);
}

至此,框架已经搭好,现在只需要在添加的几个函数中中添加具体切换逻辑

void CComboTestDlg::OnCbnSelchangeComboOld()
{
CString text;
m_cmbOld.GetWindowText(text);
if (text == _T("custom"))
{ // 切换到手动编辑下拉框
m_cmbOld.ShowWindow(SW_HIDE);
m_cmbNew.ShowWindow(SW_SHOW);
m_cmbNew.SetFocus();
}
else
{
MessageBox(text);
}
}
void CComboTestDlg::OnCbnSelChangeComboNew()
{
CString text;
m_cmbNew.GetWindowText(text);
if (text == _T("custom"))
{ // 重新输入
m_cmbNew.SetWindowText(_T(""));
}
else
{ // 切换到原来的下拉框
m_cmbNew.ShowWindow(SW_HIDE);
m_cmbOld.ShowWindow(SW_SHOW);
m_cmbOld.SetCurSel(m_cmbOld.FindString(, text));
MessageBox(text);
}
}
BOOL CComboTestDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_RETURN) // 回车键
{
if (m_cmbNew.GetFocus())
{
// 添加控件信息到列表上
CString text;
m_cmbNew.GetWindowText(text);
int nSelect = m_cmbNew.FindString(, text);
if (nSelect == -)
{ // 若列表项中不存在则添加控件信息到下拉框中
g_strText.push_back(text);
m_cmbOld.AddString(text);
m_cmbNew.AddString(text);
}
else
{ // 若已存在则显示原来的下拉框并定位到该列表项下
m_cmbNew.ShowWindow(SW_HIDE);
m_cmbOld.ShowWindow(SW_SHOW);
m_cmbOld.SetCurSel(nSelect);
}
MessageBox(text);
}
}
} return CDialog::PreTranslateMessage(pMsg);
}

至此功能完成,可以根据实际需求把一些代码进行封装,毕竟MFC对API封装得都很浅。

功能具体描述如下

1. 初始对话框,显示的是Drop List类型的组合框。

2. 选中custom以外的列表项时,会弹出窗口显示该列表项的文本。

3. 选中custom时,会进入编辑模式,下拉框变成Dropdown类型。

4. 编辑完后按回车,如果文本已经在列表项中,则会弹出窗口显示该文本然后组合框变回Drop List类型,否则把输入文本添加到列表项末尾。

5. 组合框是Dropdown类型时,若选择了custom之外的列表项,组合框会便会Drop List类型。

MFC的组合框(ComboBox)控件切换下拉样式的更多相关文章

  1. MFC中控制COMBOBOX控件的下拉框高度

    这是使用Visual Stiduo的小技巧哦.今天上网找来的.在界面设计面板上,点击ComboBox的下拉箭头,会另外出现一个虚边框.可以调整其大小.这个就是实现运行的时候下拉边框的默认值啦.

  2. 支持各种控件上/下拉刷新的android-pulltorefresh

    android- pulltorefresh 一个强大的拉动刷新开源项目,支持各种控件下拉刷新,如ListView.ViewPager.WevView. ExpandableListView.Grid ...

  3. (转载)VC/MFC 工具栏上动态添加组合框等控件的方法

    引言 工具条作为大多数标准的Windows应用程序的 一个重要组成部分,使其成为促进人机界面友好的一个重要工具.通过工具条极大方便了用户对程序的操作,但是在由Microsoft Visual C++开 ...

  4. VC/MFC 工具栏上动态添加组合框等控件的方法

    引言 工具条作为大多数标准的Windows应用程序的一个重要组成部分,使其成为促进人机界面友好的一个重要工具.通过工具条极大方便了用户对程序的操作,但是在由Microsoft Visual C++开发 ...

  5. WPF中。。DataGrid 实现时间控件和下拉框控件

    DatePicker 和新的 DataGrid 行 用户与 DataGrid 中日期列的交互给我造成了很大的麻烦. 我通过将一个 Data Source 对象拖动到 WPF 窗口上,创建了一个 Dat ...

  6. 代理Delegate的小应用(代理日期控件和下拉框)

    前言 在平时关于表格一类的的控件使用中,不可避免需要修改每个Item的值,通过在Item中嵌入不同的控件对编辑的内容进行限定,然而在表格的Item中插入的控件始终显示,当表格中item项很多的时候,会 ...

  7. 几种常用的控件(下拉框 可选框 起止日期 在HTML页面直接读取当前时间)

    下拉框 <div class="form-group">                        <label class="col-xs-3 c ...

  8. bootstrap selectpicker控件select下拉框动态数据无法回显的问题

    有关于selectpicker下拉框数据回显的问题,当查看一个对象的属性的时候, 发现有关于selectpicker的下拉框并没有将返回的数据进行回显,显示的都是请选择, 经查证,当查看属性的时候,他 ...

  9. Qt qml listview 列表视图控件(下拉刷新、上拉分页、滚动轴)

    Qt qml listview下拉刷新和上拉分页主要根据contentY来判断.但要加上顶部下拉指示器.滚动条,并封装成可简单调用的组件,着实花了我不少精力:) [先看效果]    [功能] 下拉刷新 ...

随机推荐

  1. HDU 1714 math

    #include<stdio.h>#include<string.h>#include<iostream>#include<iomanip>#inclu ...

  2. 快速切题 sgu118. Digital Root 秦九韶公式

    118. Digital Root time limit per test: 0.25 sec. memory limit per test: 4096 KB Let f(n) be a sum of ...

  3. (zz)设置单元格的宽度和高度

    (zz)设置单元格的宽度和高度 博客分类: POI生成Excel   在Excel中,单元格的宽度其实就是列的宽度,因为Excel假设这一列的单元格的宽度肯定一致.所以要设置单元格的宽度,我们就得从列 ...

  4. bzoj1600

    题解: 简单dp 显然不能超过一半 代码: #include<bits/stdc++.h> using namespace std; ][]; int main() { f[][]=; s ...

  5. bzoj1082

    题解: 暴搜+二分+剪枝 二分答案,暴力判断是否有解 然后加上剪枝 代码: #include<bits/stdc++.h> using namespace std; ; int rest, ...

  6. 未能加载文件或程序集“Microsoft.Office.Interop.Excel

    解决方法:未能加载文件或程序集“Microsoft.Office.Interop.Excel...”   2010-07-25 08:06:15   来源:源码之家 站长整理    [大 中 小]   ...

  7. <小常识>

    1,DOS(磁盘操作系统) 2,人机交互: (1):图形化界面(Graphical User interface GUI), (2):命令行方式(Command Line Interface CLI) ...

  8. STL标准库-容器适配器

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 上一节介绍了仿函数适配器,这节主要介绍容器适配器和迭代器适配器的概念,其实容器适配器和迭代器其适配器就是封装了一些其他class ...

  9. L220

    He must not allow this unusual barrier (obstacle) to stop him from fighting against the enemy.他绝不能让这 ...

  10. L212

    Just 33 minutes into the New Year, NASA's New Horizons probe made space exploration history, flying ...