MFC的組合框(ComboBox)控制項切換下拉樣式

來源:互聯網
上載者:User

標籤:ack   包含   etc   ++   png   set   之間   ide   基於   

由於課題的需求需要做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 = 0; 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(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類型。

 

MFC的組合框(ComboBox)控制項切換下拉樣式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.