MFC動態創建控制項並添加消息映射

来源:https://www.cnblogs.com/timefiles/archive/2022/11/20/16909479.html
-Advertisement-
Play Games

指定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() 函數,後面有時間再研究。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • static_assert是c++11添加的新語法,它可以使我們在編譯期間檢測一些斷言條件是否為真,如果不滿足條件將會產生一條編譯錯誤信息。 使用靜態斷言可以提前暴露許多問題到編譯階段,極大的方便了我們對代碼的排錯,提前將一些bug扼殺在搖籃里。 然而有時候靜態斷言並不能如我們預期的那樣工作,今天就 ...
  • # 1.函數的作用域 # 全局變數的作用域: # 一般在函數體外定義的變數成為全局變數,在函數內部定義的變數稱為局部變數。 # 全局變數所有作用域都可用,局部變數只能在本函數可用,變 # 量的使用順序是,局部變數 > 全局變數, 也就是說:優先使用局部變數 # # global關鍵字: # 為瞭解決 ...
  • WEB開發會話技術01 1.會話 Web開發中,用到的4種會話跟蹤技術 - 博客園 (cnblogs.com) 會話的基本介紹 什麼是會話? 會話可簡單理解為:用戶開一個瀏覽器,點擊多個超鏈接,訪問伺服器多個web資源,然後關閉瀏覽器,整個過程稱之為一個會話。 會話過程中要解決的一些問題: (1)每 ...
  • C++的運算符重載:使對象的運算表現得和編譯器內置類型一樣 如下代碼,如果T是整形,那很好理解,但是如果 T 是一個 Student 類, a + b ?怎麼操作,兩個學生類怎麼相加? 這個就是我們要說的運算符重載問題 template T sum(T a,T b){ return a + b; / ...
  • 一般,做資料庫表設計時,很多情況下,我們都至少需要一個日期欄位來記錄操作相關。 而這種表示日期的欄位,我們使用 datetime 類型比較多,但是如果使用 datetime 類型,直接前端拿日期時,我們會發現拿到日期格式是 2022-11-20T11:10:00.000+00:00 這種的,但我們一 ...
  • C++ 讀取文件及保留小數方法 做圖論作業時,需要從文件中讀取整型數據。之前都是在標準輸入輸出流中讀取和輸出。今小記一下。 讀取文件 使用文件流ifstream 最簡潔的方法是使用文件流: ifstream infile(filename) 假設 test.txt 文件中存放5 6: ifstrea ...
  • 一.小結 1.電腦是儲存和處理數據的電子設備 2.電腦包括硬體和軟體兩個部分 3.硬體是電腦中可以看見的物理部分 4.電腦程式,也就是通常所說的軟體,是一些看不見的指令,它們控制硬體完成任務 5.電腦程式設計就是編寫電腦執行的指令(即代碼) 6.中央處理器(CPU)是電腦的大腦。它是內 ...
  • 接上回,聊聊函子 functor。 functor 是一個容器。該容器的 value 屬性指向被包裹的數據;該容器的 map 方法對容器進行映射變換。 以下代碼實現一個最普通的 functor,稱之為 Just, 根據 map 的傳參 fn 對 value 進行變換: class Just<T> { ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...