指定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() 函数,后面有时间再研究。

MFC动态创建控件并添加消息映射的更多相关文章

  1. 【转载】MFC动态创建控件及其消息响应函数

    原文:http://blog.sina.com.cn/s/blog_4a08244901014ok1.html 这几天专门调研了一下MFC中如何动态创建控件及其消息响应函数. 参考帖子如下: (1)h ...

  2. MFC动态创建控件及其消息响应函数

    这几天专门调研了一下MFC中如何动态创建控件及其消息响应函数. 参考帖子如下: (1)http://topic.csdn.net/u/20101204/13/5f1b1e70-2f1c-4205-ba ...

  3. MFC 动态创建控件

    动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的.   一.创建动态控件:   为了对照,我们先来看一下静态控件的创建.   放置静态控件时必须先建立一个容器,一 ...

  4. 小子给大家分享一个或者多个新手创建tableview经常会遇到的坑(动态创建控件,xib的重用)

    小子最近做了一个根据接口返回的数据在Cell中动态创建控件,感觉应该会一部分人卡在这里,小子就跟大家分享一下: 1.控件重复创建:这个问题出现的原因是动态创建的cell内容的时候,无法进行重用设置,所 ...

  5. VisionPro笔记(1):动态创建控件

     VisionPro学习笔记(1):动态创建控件 有的时候可能需要在程序中动态创建控件,VisionPro实例中提供了一例动态创建Blob控件的方法.当然,动态创建过多的控件会极大的消耗系统的资源,建 ...

  6. delphi动态创建控件

    动态创建控件 其实动态创建控件很简单,相信看过本文后你会全明白的. 1 先在单元的initialization 部分注册它,(这样在单元使用时会自动注册的)如: RegisterClass( TBut ...

  7. mfc 动态为控件添加事件2

    重载窗口过程 为动态控件绑定事件 一.重载窗口过程处理函数 CWnd::WindowProc virtual LRESULT WindowProc( UINT message, WPARAM wPar ...

  8. mfc 动态为控件添加事件1

    知识点: 认识窗口过程 GetWindowLong SetWindowLong 为动态控件绑定事件 一.获取窗口过程 二.设置新窗口过程 .书写一个新窗口过程函数 窗口过程格式 LRESULT CAL ...

  9. 在DELPHI中动态创建控件以及控件的事件

    在DELPHI中我们经常要动态的创建控件以及控件的事件.例如,我们可能想根据程序需要动态的创建一些Tshape组件来创建某个图形,并使得在鼠标移动上去之后可以完成某些操作.这一般需要需要三步: 生成一 ...

  10. Winfrom动态创建控件

    FlowLayoutPanel flowLayoutPanel1 = new FlowLayoutPanel();for (int i = 0; i < 9; i++){    Button b ...

随机推荐

  1. 5.13 汇编语言:仿写For循环语句

    循环语句(for)是计算机编程中的一种基本控制结构,它允许程序按照指定的次数或范围重复执行一段代码块.for循环在处理需要进行迭代操作的情况下非常有用,它使得程序可以更加方便地控制循环的次数.一般来说 ...

  2. P4396 [AHOI2013] 作业 题解

    题目链接:作业 其实可以类似"HH的项链"转化为偏序问题再 cdq 分治.不过这题感觉莫队然后值域分块很好写啊,基本不用动脑. 考虑查询的两个信息: \(a \le x\le b\ ...

  3. 如果在循环中不改变vector的大小,C++编译器是否会将.size()优化为常数?

      在C++中,可以使用以下代码计算vector<int>中所有元素的和: vector<int> v = {1, 3, 7, 9}; sums = 0; for (int i ...

  4. win10远程桌面连接,使用正确的用户名和密码仍然不能成功连接

    最近笔记本重置后,台式使用"远程桌面连接"远程笔记本失败了,总是提示"登录没有成功". 开始自查:win10专业版,允许远程的相关设置也都开了,连接的ip正确, ...

  5. NEMU PA 3-3 实验报告

    一.实验目的 在上一章PA3-2中,我们实现了分段机制,将48位的虚拟地址vaddr转换成了laddr.为什么不是paddr呢?这就要说到这一章要完成的东西:**分页机制 **. 从80386开始,计 ...

  6. Python 中Time 模块

    python的time内置模块是一个与时间相关的内置模块,很多人喜欢用time.time()获取当前时间的时间戳,利用程序前后两个时间戳的差值计算程序的运行时间,如下: 1.使用time.time() ...

  7. CORS就是跨域吗?

    首先,跨域的域是什么? 跨域的英文是:Cross-Origin. Origin 中文含义为:起源,源头,出生地. 在跨域中,"域"指的是一个 Web 资源(比如网页.脚本.图片等) ...

  8. Centos7使用memtester测试内存

    memtester http://pyropus.ca/software/memtester/ 下载并编译, 不用安装 wget http://pyropus.ca/software/memteste ...

  9. Django实战之文件上传下载

    项目介绍 最近学习django,通过文件上传下载这个小项目,总结下常用的知识点. 做这个案例我有以下需求: 1.要支持一次上传多个文件 2.支持上传后记录上传的数据以及列表展示 3.支持下载和删除文件 ...

  10. win32 - 控制台聊天

    仅适用于同一台电脑的两个进程聊天,对于不同电脑之前的聊天需要依靠tcp/ip协议. 两个进程是通过发送WM_COPYDATA 消息来传输字节的. 代码如下: Server.cpp #include & ...