由于课题的需求需要做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. Awk 从入门到放弃(3) —- 内置变量

    转:http://www.zsythink.net/archives/1374 NF :当前行的字段个数 NR:  行号 FNR: 各文件分别计数的行号 RS: 输入行分隔符 ORS:输出行分隔符 内 ...

  2. SQL Server 调优系列玩转篇三(利用索引提示(Hint)引导语句最大优化运行)

    前言 本篇继续玩转模块的内容,关于索引在SQL Server的位置无须多言,本篇将分析如何利用Hint引导语句充分利用索引进行运行,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析. 闲 ...

  3. [译].Net 4.5 的五项强大新特性

    本文原文:Five Great .NET Framework 4.5 Features 译者:冰河魔法师 目录 介绍 特性一:async和await 特性二:Zip压缩 特性三:正则表达式执行超时 特 ...

  4. <NET CLR via c# 第4版>笔记 第12章 泛型

    泛型优势: 源代码保护 使用泛型算法的开发人员不需要访问算法的源代码.(使用c++模板的泛型技术,算法的源代码必须提供给使用算法的用户) 类型安全 向List<DateTime>实例添加一 ...

  5. 转:ios导航栏设置

    原帖:http://www.cocoachina.com/industry/20131104/7287.html 本文提供的代码需要用Xcode 5来执行.如果你还在使用老版本的Xcode,那么在运行 ...

  6. Linux IO模式-阻塞io、非阻塞io、多路复用io

    一 概念说明 在进行解释之前,首先要说明几个概念: - 用户空间和内核空间 - 进程切换 - 进程的阻塞 - 文件描述符 - 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对3 ...

  7. MQTT连接服务器返回2

    /********************************************************************************* * MQTT连接服务器返回2 * ...

  8. Springboot中的连接池

    pom.xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-ja ...

  9. Ubuntu中敲写c语言步骤

    1.进入Ubuntu界面 1.1按快捷键 Ctrl + Alt + T: 1.2 安装vim:输入 sudo apt-get install vim: 1.3 安装gcc:输入 sudo apt-ge ...

  10. js窗口拖动 模版

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...