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
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...