指定ID 在類中聲明並定義按鈕控制項的起始ID,以控制項的類型和功能對動態控制項ID進行分組,每組最好定義一個自己的起始ID方便管理: #define IDC_CONTROL_START 1000 #define IDC_BTN_START IDC_CONTROL_START+100 #define ID ...
目錄
指定ID
在類中聲明並定義按鈕控制項的起始ID,以控制項的類型和功能對動態控制項ID進行分組,每組最好定義一個自己的起始ID方便管理:
#define IDC_CONTROL_START 1000
#define IDC_BTN_START IDC_CONTROL_START+100
#define IDC_STA_START IDC_CONTROL_START+200
#define IDC_EIT_START IDC_CONTROL_START+300
#define IDC_CMB_START IDC_CONTROL_START+400
起始ID可以設置大一點,避免與窗體內部的控制項ID重覆,上面定義了四種控制項的起始ID。
對象指針
根據動態控制項的生命周期,在對應的作用域裡面定義控制項對象的指針,一般會定義在頭文件里保證控制項和窗體生命周期相同:
std::vector<CButton*>pBtn;
std::vector<CStatic*>pSta;
std::vector<CEdit*>pCet;
std::vector<CComboBox*>pCmb;
註:使用vector容器便於擴充控制項數量,需添加頭文件vector。
建立對象
在類的OnInitDialog()函數中動態創建按鈕:
int count = 3;
int width = 100;
int height = 50;
int space = 20;
pBtn.resize(count);
pSta.resize(count);
pCet.resize(count);
pCmb.resize(count);
int L, T, R, B;
CWnd* pWnd = this;
//可以使用其它控制項作為父窗體,但消息處理會很麻煩
//pWnd = GetDlgItem(IDC_STATIC_GROUP);
DWORD dwStyle;
CRect rect;
for (size_t i = 0; i < count; i++)
{
L = 20 + i * (width + space);
T = 20 + 0 * (height + space);
dwStyle = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_FLAT;
rect = CRect(L, T, L + width, T + height);
pBtn[i] = new CButton();
pBtn[i]->Create(_T("按鈕"), dwStyle, rect, pWnd, IDC_BTN_START + i);
T = 20 + 1 * (height + space);
dwStyle = WS_CHILD | WS_VISIBLE | SS_CENTER;
rect = CRect(L, T, L + width, T + height);
pSta[i] = new CStatic();
pSta[i]->Create(_T("文本"), dwStyle,rect, pWnd, IDC_CONTROL_START + 200);
T = 20 + 2 * (height + space);
dwStyle = ES_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER;
rect = CRect(L, T, L + width, T + height);
pCet[i] = new CEdit();
pCet[i]->Create(dwStyle,rect , pWnd, IDC_CONTROL_START + 300);
pCet[i]->SetWindowText(_T("編輯"));
//下拉框的高度必須設大一點,防止不能選中項
T = 20 + 3 * (height + space);
dwStyle = WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST | CBS_HASSTRINGS;
rect = CRect(L, T, L + width, T + height + 100);
pCmb[i] = new CComboBox();
pCmb[i]->Create(dwStyle, rect, pWnd, IDC_CONTROL_START + 400);
pCmb[i]->AddString(_T("1"));
pCmb[i]->AddString(_T("2"));
pCmb[i]->AddString(_T("3"));
}
上面的控制項佈局可以按自己的來,重要的是Create()函數,每個控制項的Create()函數不一樣,以最底層CWnd類的Create()函數進行說明:
virtual BOOL Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd, UINT nID,
CCreateContext* pContext = NULL);
參考:https://learn.microsoft.com/zh-cn/cpp/mfc/reference/cwnd-class?view=msvc-170#create
- lpszClassName:指向以 null 結尾的字元串的指針,該字元串包含已註冊的系統視窗類的名稱;或者為預定義的系統視窗類的名稱。
- lpszWindowName:指向以 null 結尾的字元串的指針,該字元串包含視窗顯示名稱;否則為 NULL,表示沒有視窗顯示名稱。
- dwStyle:視窗樣式的按位組合 (OR), WS_POPUP 選項不是有效樣式。
- rect:視窗相對於父視窗左上角的大小和位置。
- pParentWnd:指向父視窗的指針。
- nID:視窗的 ID。
- pContext:指向 CCreateContext 結構的指針,該結構用於自定義應用程式的文檔視圖體繫結構。
lpszClassName、lpszWindowName、pContext這三個參數不確定的情況下,可以傳入NULL。
其它控制項的Create()函數參考 MFC 類 中的控制項類
運行效果如下圖:
控制項樣式
如果給定 WS_VISIBLE 樣式,Windows發送按鈕控制項所需的所有信息激活和顯示按鈕,還可以將以下 視窗樣式 應用於控制項:
- 始終WS_CHILD
- 通常WS_VISIBLE
- 少見WS_DISABLED
- 對控制項分組的WS_GROUP
- 包含控制項的WS_TABSTOP 按tab鍵順序
每種控制項還有自己的樣式,詳細內容見 MFC使用的樣式
消息映射
一個MFC的消息響應函數在程式中有以下三部分:
- 函數原型:頭文件中在兩個AFX_MSG註釋巨集之間是消息響應函數原型的聲明。
- 函數實現:源文件中的消息響應函數的實現代碼。
- 關聯消息和消息響應函數的巨集:在源文件AFX_MSG_MAP註釋巨集之間的消息映射巨集,用來關聯消息和消息響應函數。
關於消息映射的更多內容參考 消息映射(MFC)。
按鈕單擊
可以使用常規方法,根據ID為按鈕綁定單擊的消息響應函數:
ON_BN_CLICKED(IDC_BTN_START + 0, &CMFCApplication1Dlg::OnBtnClik)
如果生成的按鈕比較多,一個個處理會很麻煩,需要使用批量綁定,批量綁定按鈕單擊消息響應函數的步驟:
- 在對話框類的定義文件(.h文件)中聲明消息響應函數OnBtnClick。
afx_msg void OnBtnClick(UINT uID);
註:OnBtnClick函數的參數nID代表響應函數對應按鈕控制項的ID號,單個按鈕可不設參數。
- 在對話框類的函數實現文件(.cpp文件)中定義消息映射ON_COMMAND_RANGE (多個按鈕),根據其輸入ID分辨具體響應那個按鈕。
ON_COMMAND_RANGE(IDC_BTN_START + 0, IDC_BTN_START + 3, &CMFCApplication1Dlg::OnBtnClik)
註:在函數實現文件中的消息映射部分(BEGIN_MESSAGE_MAP與END_MESSAGE_MAP之間)定義按鈕控制項與其消息響應函數之間的映射關係。
- 實現消息響應函數OnBtnClick,在對話框類的函數實現文件(.cpp文件)中給出具體的按鈕消息響應。
void CMFCApplication1Dlg::OnBtnClik(UINT uID)
{
int id = uID -IDC_BTN_START;
CString str;
str.Format("當前ID %d", id);
int result = MessageBox(str, TEXT("確認"), MB_YESNO);
}
組合框選中
使用ON_CBN_SELCHANGE消息:
ON_CBN_SELCHANGE(IDC_CMB_START, &CMFCApplication1Dlg::OnSelComChange)
聲明消息響應函數:
afx_msg void OnSelComChange();
實現消息響應函數:
void CMFCApplication1Dlg::OnSelComChange()//選擇下拉框某一列的時候得到響應
{
for (size_t i = 0; i < pCmb.size(); i++)
{
if (pCmb[i]==GetFocus())
{
CString str(_T(""));//獲取當前下拉框的值
pCmb[i]->GetLBText(pCmb[i]->GetCurSel(), str);//獲取CComBox下拉框當前選中的值
MessageBox(str, TEXT("確認"), MB_OK);
}
}
}
疑問:明明對一個控制項ID映射了消息響應函數,但後面的組合框控制項都能進入OnSelComChange() 函數,後面有時間再研究。