博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MFC的组合框(ComboBox)控件切换下拉样式
阅读量:4975 次
发布时间:2019-06-12

本文共 5268 字,大约阅读时间需要 17 分钟。

由于课题的需求需要做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 
std::vector
g_strText = { _T("cpp"), _T("java"), _T("python"), _T("custom") };

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

for (size_t i = 0; i < g_strText.size(); i++)    {    // C++11中可以用
的std::extent
::value取得text数组大小 m_cmbOld.AddString(g_strText[i]); m_cmbNew.AddString(g_strText[i]); } m_cmbOld.SetCurSel(0); // 默认选择第一项("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(0, 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(0, text);                if (nSelect == -1)                {    // 若列表项中不存在则添加控件信息到下拉框中                    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类型。

 

转载于:https://www.cnblogs.com/Harley-Quinn/p/7798815.html

你可能感兴趣的文章
组件:slot插槽
查看>>
Nginx配置文件nginx.conf中文详解(转)
查看>>
POJ 1308 Is It A Tree?(并查集)
查看>>
N进制到M进制的转换问题
查看>>
springIOC第一个课堂案例的实现
查看>>
求输入成绩的平均分
查看>>
php PDO (转载)
查看>>
wordpress自动截取文章摘要代码
查看>>
[置顶] 一名优秀的程序设计师是如何管理知识的?
查看>>
highcharts 图表实例
查看>>
highcharts曲线图
查看>>
extjs动态改变样式
查看>>
宏定义
查看>>
笔记:git基本操作
查看>>
生成php所需要的APNS Service pem证书的步骤
查看>>
JavaWeb之JSON
查看>>
HOT SUMMER 每天都是不一样,积极的去感受生活 C#关闭IE相应的窗口 .
查看>>
optionMenu-普通菜单使用
查看>>
2016-2017-2点集拓扑作业[本科生上课时]讲解视频
查看>>
【MemSQL Start[c]UP 3.0 - Round 1 C】 Pie Rules
查看>>