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
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...