MFC动态控件使用

本文详细介绍了在VisualStudio2022环境下使用MFC创建各种控件(如按钮、编辑框等)的方法,包括控件ID设置、窗口风格、控件位置以及动态创建步骤,还提供了在MFC工程中实际应用的示例代码。
摘要由CSDN通过智能技术生成

MFC动态控件使用

VS2022 MFC

1.前言

1.1 控件ID号:

ID号是控件的标识,创建控件前必须先为它设置一个ID号。

1.2 控件对象:

	按钮控件      		CButton  包括普通按钮、单选按钮和复选按钮)
	编辑控件      		CEdit
	静态文本控件  		CStatic 
	标签控件      		CTabCtrl 
	旋转控件      		CSpinButtonCtrl 
	滑标控件      		CSliderCtrl 
	多信息编辑控件    	CRichEditCtrl 
	进度条控件    		CProgressCtrl 
	滚动条控件    		CSrcollBar 
	组合框控件    		CComboBox 
	列表框控件    		CListBox 
	图像列表控件  		CImageCtrl 
	树状控件      		CTreeCtrl 
	动画控件      		CAnimateCtrl 

1.3 窗口风格(dwStyle):

dwStyle指定按钮风格,可以是按钮风格与窗口风格的组合,取值有:

窗口风格:

	WS_CHILD 		子窗口,必须有 
	WS_VISIBLE 		窗口可见,一般都有 
	WS_DISABLED 	禁用窗口,创建初始状态为灰色不可用的按钮时使用 
	WS_TABSTOP 		可用Tab键选择 
	WS_GROUP 		成组,用于成组的单选按钮中的第一个按钮 

按钮风格:

	BS_PUSHBUTTON 				下压式按钮,也即普通按钮 
	BS_AUTORADIOBUTTON 			含自动选中状态的单选按钮 
	BS_RADIOBUTTON 				单选按钮,不常用 
	BS_AUTOCHECKBOX 			含自动选中状态的复选按钮 
	BS_CHECKBOX 				复选按钮,不常用 
	BS_AUTO3STATE 				含自动选中状态的三态复选按钮 
	BS_3STATE 					三态复选按钮,不常用 

以上风格指定了创建的按钮类型,不能同时使用,但必须有其一。

其他

	BS_BITMAP 按钮上将显示位图 
	BS_DEFPUSHBUTTON 设置为默认按钮,只用于下压式按钮,一个对话框中只能指定一个默认按钮 

1.4 控件位置(rect):

指定按钮的大小和位置。

2.动态创建控件步骤

2.1 new()

创建动态控件用new调用CButton构造函数生成一个实例:
CButton *p_MyBut = new CButton();

2.2 Create()

函数原型如下:
BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

2.3 创建过程

创建静态文本

// 创建动态控件 - static
CStatic * CDynCtrl::CreateDynCtrlStatic(int nID,DWORD nStyle,CRect rect)
{
	CStatic* p_Static = new CStatic();
	//ASSERT_VALID(p_Static);

	CString m_Caption;
	BOOL bNameValid = m_Caption.LoadString(nID);
	//ASSERT(bNameValid);
	p_Static->Create(m_Caption, WS_CHILD | WS_VISIBLE  | nStyle, rect, this, nID);  //创建按钮  
	p_Static->SetFont(&mFont);
	return p_Static;
}

创建编辑框

// 创建动态控件 - Edit
CEdit * CDynCtrl::CreateDynCtrlEdit(int nID, DWORD nStyle, CRect rect)
{
	CEdit* p_Edit = new CEdit();
	//ASSERT_VALID(p_Edit);

	CString m_Caption;
	BOOL bNameValid = m_Caption.LoadString(nID);
	//ASSERT(bNameValid);
	p_Edit->Create(WS_CHILD | WS_VISIBLE  | nStyle, rect, this, nID);  //创建按钮  
	p_Edit->SetFont(&mFont);
	return p_Edit;
}

创建按钮

// 创建动态控件 - Button
CButton* CDynCtrl::CreateDynCtrlButton(int nID, DWORD nStyle, CRect rect)
{
	CButton* p_Button = new CButton();
	CString m_Caption;
	//ASSERT_VALID(p_Button);

	BOOL bNameValid = m_Caption.LoadString(nID);
	//ASSERT(bNameValid);

	p_Button->Create(m_Caption, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | nStyle, rect, this, nID);  //创建按钮  
	p_Button->SetFont(&mFont);
	return p_Button;
}

3.实例

3.1 创建MFC工程

在这里插入图片描述

3.2 插入DIalog

	新插入一个子对话框,IDD_DIALOG_DYNCTRL。后续将在该对话框内动态生成控件。

3.2 添加动态控件ID

	打开资源中的`“String Table”`,在空白行上双击鼠标,这时会弹出一个ID属性对话框,在其中的ID编辑框中输入ID,Caption(标题)框不能为空,为空会导致创建失败,这里输入的是按钮上要显示的文字。

在这里插入图片描述
在这里插入图片描述

好像直接使用#define也行。

#define IDC_DYNCTRL_STATIC_IP 1101
#define IDC_DYNCTRL_EDIT_IP 1102
#define IDC_DYNCTRL_STATIC_PORT 1103
#define IDC_DYNCTRL_EDIT_PORT 1104

3.3 主对话框.h

// MFC_DynCtrlDlg.h: 头文件
//

#pragma once
#include"CDynCtrl.h" // 子对话框类

// CMFCDynCtrlDlg 对话框
class CMFCDynCtrlDlg : public CDialogEx
{
// 构造
public:
	CMFCDynCtrlDlg(CWnd* pParent = nullptr);	// 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_MFC_DYNCTRL_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedButtonCreateDynctrl();

	CDynCtrl DynCtrl; // 子对话框类对象
};

3.4 主对话框cpp


// MFC_DynCtrlDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "MFC_DynCtrl.h"
#include "MFC_DynCtrlDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCDynCtrlDlg 对话框



CMFCDynCtrlDlg::CMFCDynCtrlDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MFC_DYNCTRL_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCDynCtrlDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMFCDynCtrlDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_CREATE_DYNCTRL, &CMFCDynCtrlDlg::OnBnClickedButtonCreateDynctrl)
END_MESSAGE_MAP()


// CMFCDynCtrlDlg 消息处理程序

BOOL CMFCDynCtrlDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMFCDynCtrlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCDynCtrlDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCDynCtrlDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


// 创建动态控件
void CMFCDynCtrlDlg::OnBnClickedButtonCreateDynctrl()
{
	// TODO: 在此添加控件通知处理程序代码
	DynCtrl.DoModal();
}

3.5 子对话框.h

#pragma once
#include "afxdialogex.h"


// CDynCtrl 对话框

class CDynCtrl : public CDialogEx
{
	DECLARE_DYNAMIC(CDynCtrl)

public:
	CDynCtrl(CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CDynCtrl();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_DIALOG_DYNCTRL };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL OnInitDialog();

	CStatic * CreateDynCtrlStatic(int nID, DWORD nStyle, CRect rect); // 创建动态控件 - static
	CEdit * CreateDynCtrlEdit(int nID, DWORD nStyle, CRect rect); // 创建动态控件 - Edit
	CButton * CreateDynCtrlButton(int nID, DWORD nStyle, CRect rect); // 创建动态控件 - Button
	
	void Init(); // 初始化

	CStatic * pCtrlStatic[2];
	CEdit * pCtrlEdit[2];
	//CButton* pCtrlButton[2];

	CFont mFont/*,FontStatic, FontEdit*/;
	CString FontName;
	int FontSize;
	afx_msg void OnBnClickedOk();
	afx_msg void OnBnClickedCancel();

	// 删除动态控件
	void DeleteDynCtrl();
	afx_msg void OnBnClickedCheck1();
	CButton mCheck;
};

3.6 子对话框.cpp

// CDynCtrl.cpp: 实现文件
//

#include "pch.h"
#include "MFC_DynCtrl.h"
#include "afxdialogex.h"
#include "CDynCtrl.h"

#define IDC_DYNCTRL_STATIC_IP 1101

// CDynCtrl 对话框

IMPLEMENT_DYNAMIC(CDynCtrl, CDialogEx)

CDynCtrl::CDynCtrl(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DIALOG_DYNCTRL, pParent)
{
	FontName = _T("宋体");
	FontSize = 150;
	mFont.CreatePointFont(FontSize, FontName, NULL);// 设置控件字体
}

CDynCtrl::~CDynCtrl()
{
}

void CDynCtrl::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_CHECK1, mCheck);
}


BEGIN_MESSAGE_MAP(CDynCtrl, CDialogEx)
	ON_BN_CLICKED(IDOK, &CDynCtrl::OnBnClickedOk)
	ON_BN_CLICKED(IDCANCEL, &CDynCtrl::OnBnClickedCancel)
	ON_BN_CLICKED(IDC_CHECK1, &CDynCtrl::OnBnClickedCheck1)
END_MESSAGE_MAP()


// CDynCtrl 消息处理程序
BOOL CDynCtrl::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO:  在此添加额外的初始化
	mCheck.SetCheck(1);
	Init();

	return TRUE;  // return TRUE unless you set the focus to a control
	// 异常: OCX 属性页应返回 FALSE
}

// 创建动态控件 - static
CStatic * CDynCtrl::CreateDynCtrlStatic(int nID,DWORD nStyle,CRect rect)
{
	CStatic* p_Static = new CStatic();
	//ASSERT_VALID(p_Static);

	CString m_Caption;
	BOOL bNameValid = m_Caption.LoadString(nID);
	//ASSERT(bNameValid);
	p_Static->Create(m_Caption, WS_CHILD | WS_VISIBLE  | nStyle, rect, this, nID);  //创建按钮  
	p_Static->SetFont(&mFont);
	return p_Static;
}

// 创建动态控件 - Edit
CEdit * CDynCtrl::CreateDynCtrlEdit(int nID, DWORD nStyle, CRect rect)
{
	CEdit* p_Edit = new CEdit();
	//ASSERT_VALID(p_Edit);

	CString m_Caption;
	BOOL bNameValid = m_Caption.LoadString(nID);
	//ASSERT(bNameValid);
	p_Edit->Create(WS_CHILD | WS_VISIBLE  | nStyle, rect, this, nID);  //创建按钮  
	p_Edit->SetFont(&mFont);
	return p_Edit;
}

// 创建动态控件 - Button
CButton* CDynCtrl::CreateDynCtrlButton(int nID, DWORD nStyle, CRect rect)
{
	CButton* p_Button = new CButton();
	CString m_Caption;
	//ASSERT_VALID(p_Button);

	BOOL bNameValid = m_Caption.LoadString(nID);
	//ASSERT(bNameValid);

	p_Button->Create(m_Caption, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | nStyle, rect, this, nID);  //创建按钮  
	p_Button->SetFont(&mFont);
	return p_Button;
}


void CDynCtrl::Init()
{
	DWORD nStyle = NULL;
	CRect rectStatic,rectEdit,rectButton;

	/*pCtrlStatic = new CStatic[2];
	pCtrlEdit = new CEdit[2];*/
	//pCtrlButton = new CButton[2];

	//for (int i = 0; i < 2; i++)
	//{
	//	pCtrlStatic[i] = new CStatic();
	//	pCtrlEdit[i] = new CEdit();
	//	//pCtrlButton[i] = new CButton();
	//}

	int StaticWidth = 100;
	int StaticHeight = 50;
	int EditWidth = 200;
	int EditHeight = StaticHeight;
	int ButtonWidth = 80;
	int ButtonHeight = StaticHeight;
	int CtrlHorMidLine = 30;
	int CtrlVetStartLine = 20;
	int HorSpace = 10;
	int VerSpace = EditWidth+10;

	// Static - IP
	rectStatic.left = CtrlVetStartLine;
	rectStatic.right = rectStatic.left + StaticWidth;
	rectStatic.top = CtrlHorMidLine - StaticHeight / 2;
	rectStatic.bottom = CtrlHorMidLine + StaticHeight / 2;
	pCtrlStatic[0] = CreateDynCtrlStatic(IDC_DYNCTRL_STATIC_IP, nStyle, rectStatic);
	//pCtrlStatic[0].Create(_T("IP"), WS_CHILD | WS_VISIBLE | nStyle, rectStatic, this, IDC_DYNCTRL_STATIC_IP);  //创建按钮 

	// Edit - IP
	rectEdit.left = rectStatic.right + HorSpace;
	rectEdit.right = rectEdit.left + EditWidth;
	rectEdit.top = CtrlHorMidLine - EditHeight / 2;
	rectEdit.bottom = CtrlHorMidLine + EditHeight / 2;
	pCtrlEdit[0] = CreateDynCtrlEdit(IDC_DYNCTRL_EDIT_IP, nStyle, rectEdit);

	CtrlHorMidLine += VerSpace;

	// Static - Port
	rectStatic.left = CtrlVetStartLine;
	rectStatic.right = rectStatic.left + StaticWidth;
	rectStatic.top = CtrlHorMidLine - StaticHeight / 2;
	rectStatic.bottom = CtrlHorMidLine + StaticHeight / 2;
	pCtrlStatic[1] = CreateDynCtrlStatic(IDC_DYNCTRL_STATIC_PORT, nStyle, rectStatic);
	//pCtrlStatic[1].Create(_T("Port"), WS_CHILD | WS_VISIBLE | nStyle, rectStatic, this, IDC_DYNCTRL_STATIC_IP);  //创建按钮 

	// Edit - Port
	rectEdit.left = rectStatic.right+ HorSpace;
	rectEdit.right = rectEdit.left + EditWidth;
	rectEdit.top = CtrlHorMidLine - EditHeight / 2;
	rectEdit.bottom = CtrlHorMidLine + EditHeight / 2;
	pCtrlEdit[1] = CreateDynCtrlEdit(IDC_DYNCTRL_EDIT_PORT, nStyle, rectEdit);


	/*rectButton.left = 30;
	rectButton.right = rectButton.left + ButtonWidth;
	rectButton.top = 60;
	rectButton.bottom = rectButton.top + ButtonHeight;
	pCtrlButton[0] = CreateDynCtrlButton(IDC_DYNCTRL_EDIT_PORT, nStyle, rectEdit);

	rectButton.left = 60;
	rectButton.right = rectButton.left + ButtonWidth;
	rectButton.top = 60;
	rectButton.bottom = rectButton.top + ButtonHeight;
	pCtrlButton[1] = CreateDynCtrlButton(IDC_DYNCTRL_EDIT_PORT, nStyle, rectEdit);*/
}

void CDynCtrl::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	CDialogEx::OnOK();

	DeleteDynCtrl();
}


void CDynCtrl::OnBnClickedCancel()
{
	// TODO: 在此添加控件通知处理程序代码
	CDialogEx::OnCancel();

	DeleteDynCtrl();
}


// 删除动态控件
void CDynCtrl::DeleteDynCtrl()
{
	for (int i = 0; i < 2; i++)
	{
		if (pCtrlStatic[i])
		{
			pCtrlStatic[i]->DestroyWindow();
			delete pCtrlStatic[i];
		}

		if (pCtrlEdit[i])
		{
			pCtrlEdit[i]->DestroyWindow();
			delete pCtrlEdit[i];
		}

		/*if (pCtrlButton[i])
		{
			pCtrlButton[i]->DestroyWindow();
			delete pCtrlButton[i];
		}*/
	}
}



void CDynCtrl::OnBnClickedCheck1()
{
	// TODO: 在此添加控件通知处理程序代码
	int flag=mCheck.GetCheck();
	if (flag)
	{
		Init();
	}
	else
	{
		DeleteDynCtrl();
	}
}

总结

  1. 程序运行正常,动态生成功能基本完成;
  1. 指针运用还有很大问题。

原本定义pCtrlStatic和pCtrlEdit时,想使用动态分配数组,不想写死控件指针数量,但是指针运用不是太明白,迫于无奈还是写死了。

	CStatic * pCtrlStatic[2];
	CEdit * pCtrlEdit[2];
原本是想直接定义:
	CStatic * pCtrlStatic;
	CEdit * pCtrlEdit;
	pCtrlStatic = new CStatic[2];
	pCtrlEdit = new CEdit[2];
	//pCtrlButton = new CButton[2];

但是如上定义时,使用函数CreateDynCtrlStatic()创建控件后,函数返回值无法赋值给pCtrlStatic[0] 。

pCtrlStatic[0] = CreateDynCtrlStatic(IDC_DYNCTRL_STATIC_IP, nStyle, rectStatic);

会报错:
会报错。
后续再尝试动态配分配吧。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值