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
  • 隨著Aspire發佈preview5的發佈,Microsoft.Extensions.ServiceDiscovery隨之更新, 服務註冊發現這個屬於老掉牙的話題解決什麼問題就不贅述了,這裡主要講講Microsoft.Extensions.ServiceDiscovery(preview5)以及如何 ...
  • 概述:通過使用`SemaphoreSlim`,可以簡單而有效地限制非同步HTTP請求的併發量,確保在任何給定時間內不超過20個網頁同時下載。`ParallelOptions`不適用於非同步操作,但可考慮使用`Parallel.ForEach`,儘管在非同步場景中謹慎使用。 對於併發非同步 I/O 操作的數量 ...
  • 1.Linux上安裝Docken 伺服器系統版本以及內核版本:cat /etc/redhat-release 查看伺服器內核版本:uname -r 安裝依賴包:yum install -y yum-utils device-mapper-persistent-data lvm2 設置阿裡雲鏡像源:y ...
  • 概述:WPF界面綁定和渲染大量數據可能導致性能問題。通過啟用UI虛擬化、非同步載入和數據分頁,可以有效提高界面響應性能。以下是簡單示例演示這些優化方法。 在WPF中,當你嘗試綁定和渲染大量的數據項時,性能問題可能出現。以下是一些可能導致性能慢的原因以及優化方法: UI 虛擬化: WPF提供了虛擬化技術 ...
  • 引言 上一章節介紹了 TDD 的三大法則,今天我們講一下在單元測試中模擬對象的使用。 Fake Fake - Fake 是一個通用術語,可用於描述 stub或 mock 對象。 它是 stub 還是 mock 取決於使用它的上下文。 也就是說,Fake 可以是 stub 或 mock Mock - ...
  • 為.net6在CentOS7上面做準備,先在vmware虛擬機安裝CentOS 7.9 新建CentOS764位的系統 因為CentOS8不更新了,所以安裝7;簡單就一筆帶過了 選擇下載好的操作系統的iso文件,下載地址https://mirrors.aliyun.com/centos/7.9.20 ...
  • 經過前面幾篇的學習,我們瞭解到指令的大概分類,如:參數載入指令,該載入指令以 Ld 開頭,將參數載入到棧中,以便於後續執行操作命令。參數存儲指令,其指令以 St 開頭,將棧中的數據,存儲到指定的變數中,以方便後續使用。創建實例指令,其指令以 New 開頭,用於在運行時動態生成並初始化對象。方法調用指... ...
  • LiteDB 是一個輕量級的嵌入式 NoSQL 資料庫,其設計理念與 MongoDB 類似,但它是完全使用 C# 開發的,因此與 C# 應用程式的集成非常順暢。與 SQLite 相比,LiteDB 提供了 NoSQL(即鍵值對)的數據存儲方式,並且是一個開源且免費的項目。它適用於桌面、移動以及 We ...
  • 1 開源解析和拆分文檔 第三方的工具去對文件解析拆分,去將我們的文件內容給提取出來,並將我們的文檔內容去拆分成一個小的chunk。常見的PDF word mark down, JSON、HTML。都可以有很好的一些模塊去把這些文件去進行一個東西去提取。 優勢 支持豐富的文檔類型 每種文檔多樣化選擇 ...
  • OOM是什麼?英文全稱為 OutOfMemoryError(記憶體溢出錯誤)。當程式發生OOM時,如何去定位導致異常的代碼還是挺麻煩的。 要檢查OOM發生的原因,首先需要瞭解各種OOM情況下會報的異常信息。這樣能縮小排查範圍,再結合異常堆棧、heapDump文件、JVM分析工具和業務代碼來判斷具體是哪 ...