The use of common MFC controls

generalize

Substance: Bind code and control through ID, realize data exchange through DoDataExchange

Movement: Rewrite the message control to achieve interaction, pay attention to rewriting virtual functions

pch.h

Pre-Compiled Header

When compiling a program, if pch.h is used, the compiler will give priority to this file and compile it into an intermediate file. When compiling other source files, the compiler will use this intermediate file directly without recompiling pch.h. This reduces compilation time because these commonly used header files do not need to be recompiled every time

MFC Microsoft Foundation Classes

Driver, Win32 is used in the background, and MFC is used to design the interface.

MVC model view controller model (doc, data storage), view, control

Controls (icons) are identified by ID, and each page is managed by a class.

Implementation Mechanism

Encapsulated Win32

Execution phase

构造类
create 将窗口与类绑定
vie 选择ShowWindow/DoModal  文本/对话框 (可否切换)
销毁窗口
析构类

Message and control events

Establish a mapping mechanism for keyboard and mouse messages, etc., which is more convenient

Class view->Properties->Message, you can add the program corresponding to the message

IMPLEMENT_DYNCREATE(CPaintView, CView)

BEGIN_MESSAGE_MAP(CPaintView, CView)

//标准消息
ON_WM_MOUSEMOVE()
ON_WM_CHAR()
//命令消息,控件->响应事件
//通告消息,通知事件的发生,即按键的先后顺序,按下一个后另一个接受通知激活
ON_COMMAND(ID_LINE, &CPaintView::OnLine)
//用户自定义消息
    
END_MESSAGE_MAP()

kind

MFC class hierarchy diagram | Microsoft Learn

Data serialization : flatten data into json (JavaScript Object Notation, lightweight data transmission format)

1️⃣Linearly arranged array, 2️⃣Data such as {x:100, y:200}, converted into text according to actual needs 3️⃣Copy memory directly

CObject

  1. Support serialized CArchive

  2. Provide runtime class information_GetBaseClass(),GetThieClass()

​ Because classes generally do not contain class information after they are compiled.

  1. Supports dynamic creation and object diagnostic output such as child windows

AssertVaild() Dump()

key class

process

C means Class

CWinapp main function->thread (initialize the thread after creating the app)

CDocManager is used to maintain a series of document templates

CDocTemplate has the following three member variables of type CRUNTIMECLASS

InitInstance->our code

CDocument: Single document/multiple documents/dialog document template, responsible for storing data

SDI SingleDocumentInterface MDI multiple Dlg dialog

CFrameWnd: The window frame divides the area menu bar, toolbar, file directory, etc.

CView: Responsible for displaying data and embodying the framework

Some functions of InitInstance

Note that Init is only for drawing and binding, and running is the last step in WinMain. nReturnCode = pThread->Run();

// 唯一的 CPaintApp 对象
CPaintApp theApp;

// CPaintApp 初始化

BOOL CPaintApp::InitInstance()
{
    
    
    //初始化自己
	CWinAppEx::InitInstance();
	//初始化socket
	if (!AfxSocketInit())
	{
    
    
		AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
		return FALSE;
	}

	// 初始化 OLE 库 activeX
	if (!AfxOleInit())
	{
    
    
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}
	//各种manager,afx是一个工作室的名字
	AfxEnableControlContainer();
	//解决win7的任务栏bug
	EnableTaskbarInteraction(FALSE);

	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));//注册表
	LoadStdProfileSettings(16);  // 加载标准 INI 文件选项(包括 MRU)

	InitContextMenuManager();

	InitKeyboardManager();

	InitTooltipManager();
	CMFCToolTipInfo ttParams;
	ttParams.m_bVislManagerTheme = TRUE;
	theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
		RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

	// 注册应用程序的文档模板。  文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CPaintDoc),
		RUNTIME_CLASS(CMainFrame),    
		RUNTIME_CLASS(CPaintView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);


	// 分析标准 shell 命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);

	// 启用“DDE 执行”
	EnableShellOpen();
	RegisterShellFileTypes(TRUE);


	// 调度在命令行中指定的命令。  如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// 唯一的一个窗口已初始化,因此显示它并对其进行更新
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	// 仅当具有后缀时才调用 DragAcceptFiles
	//  在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生
	// 启用拖/放
	m_pMainWnd->DragAcceptFiles();
	return TRUE;
}

ID binding

CView layer

When adding response functions and variables, it is also a class operation

Define in .h, bind in .cpp, use the initialization list for the variables, and the function will be defined by double-clicking the control.

In xxxdlg.cpp

Bind to response function

void CRunBTNDlg::DoDataExchange(CDataExchange* pDX)
{
    
    
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_BTN1, BTN1);
	DDX_Control(pDX, IDC_BTN2, BTN2);
}

Bind to variable

BEGIN_MESSAGE_MAP(CRunBTNDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN1, &CRunBTNDlg::OnBnClickedBtn1)
	ON_BN_CLICKED(IDC_BTN2, &CRunBTNDlg::OnBnClickedBtn2)
END_MESSAGE_MAP()

Variable data update

UpdateData();//将编辑框的数据获取到变量
UpdateData(FALSE);//将变量的数据更新到编辑框

Document based

Line and brush

Using the DC device context device environment, a series of things about drawing are defined.

.h

protected:
	//用于绘制线条起点,当前,终点,以及按下后的状态
	CPoint m_start;
	CPoint m_cur;
	CPoint m_stop;
	BOOL m_status;

.cpp

void CPaintView::OnDraw(CDC* pDC)//重绘时调用
{
    
    
	CPaintDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	//更换后记得还原,否则在类析构后越界访问
	CPen pen(PS_DOT,1,RGB(0,255,0));//只有1的时候能看出来
	CPen* pOldPen = pDC->SelectObject(&pen);
	CBrush brush(RGB(255, 0, 0));
	CBrush* pOldBrush = pDC->SelectObject(&brush);
	if (m_status) {
    
    
		pDC->FillRect(CRect(m_start, m_cur), pOldBrush);
		//pDC->MoveTo(m_start);
		//pDC->LineTo(m_cur);
	}
	else {
    
    
		pDC->FillRect(CRect(m_start, m_stop), &brush);
		//pDC->MoveTo(m_start);
		//pDC->LineTo(m_stop);
	}
	pDC->SelectObject(pOldPen);
	pDC->SelectObject(pOldBrush);
}


//下面三个是捕获消息的

void CPaintView::OnLButtonDown(UINT nFlags, CPoint point)
{
    
    
	m_start = point;
	m_status = TRUE;
	CView::OnLButtonDown(nFlags, point); //消息传递
}


void CPaintView::OnLButtonUp(UINT nFlags, CPoint point)
{
    
    
	m_stop = point;
	InvalidateRect(NULL);
	m_status = FALSE;
	CView::OnLButtonUp(nFlags, point);
}


void CPaintView::OnMouseMove(UINT nFlags, CPoint point)
{
    
    
	if (m_status) {
    
    
		InvalidateRect(NULL);
		m_cur = point;
	}
	CView::OnMouseMove(nFlags, point);
}

Text and cursor

OnDraw section

	//解决TextOut只能显示单行文本
	CString sub = _T("");
	int y=0;
	for (int i = 0; i < m_strText.GetLength(); i++)
	{
    
    
		if (m_strText.GetAt(i) == '\r'|| m_strText.GetAt(i) == '\n')//'\n'来处理复制粘贴
		{
    
    
			pDC->TextOut(0, y, sub);
			CSize sz = pDC->GetTextExtent(sub);
			sub.Empty();
			y += sz.cy+3;//获取字符宽度,并加上行间距
			continue;
		}
		sub += m_strText.GetAt(i);
	}
	if (sub.IsEmpty() == false) 
		pDC->TextOut(0, y, sub);

	CSize sz = pDC->GetTextExtent(sub);//获取扩展信息
	//CPoint pt;
	//pt.y = y;
	//pt.x = sz.cx;
	SetCaretPos(CPoint(sz.cx+2,y));
	//::SetCaretPos(sz.cx+2,y);//系统api

Message capture part

int CPaintView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    
    
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	CClientDC dc(this);
	TEXTMETRIC tm;//text metric度量
	dc.GetTextMetrics(&tm);
	CreateSolidCaret(3, tm.tmHeight);
	ShowCaret();
	return 0;
}


void CPaintView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    
    
	CClientDC dc(this);
	m_strText += (TCHAR)nChar;
	InvalidateRect(NULL);
	CView::OnChar(nChar, nRepCnt, nFlags);
}

Menu Bar

Resource view->Menu->IDR_MAINFRAME

Description text + shortcut keys combined 画图(&P) Alt+Pseparately 新建(&N)\tCtrl+N ctrl+N

Right click to add the corresponding selection C*View class list

Response priority of overloaded functions by class View>Doc>Frame>App

Debugging Tips Output Log TRACE("%s(%d):%s\r\n", __FILE__, __LINE__, __FUNCTION__);

toolbar

Resource view->Toolbar->IDR_MAINFRAME(_256) two

Delete: Hold down and drag outside

The ID can be the same as the menu bar, and the same function will be triggered.

Dialog based

display window

ChtdMFCdllApp theApp;
ChtdMFCdllApp* pTheApp;	
CWndMain* m_WndMain;

m_WndMain = new CWndMain();
m_WndMain->Create(IDD_MAIN);
m_WndMain->ShowWindow(true);

Drag the control and write the response event

Hold down ctrl to perform batch operations. When aligning, the last one shall prevail (bold border)

AfxMessageBox

 AfxMessageBox(L"afx", MB_OK | MB_ICONINFORMATION, 0);

MessageBox

MessageBox(_T("Ok/Cancel"), _T("标题"),MB_CANCELTRYCONTINUE);
MessageBoxA(0,"hello world","hello",0);
//MB_CANCELTRYCONTINUE
//MB_ICONERROR弹出错误

TRACE

Wide byte is not supported, convert

CString temp = m_list.GetItemText(i, j);
char text[256];
memset(text, 0, sizeof(text));
size_t total;
wcstombs_s(&total, text, sizeof(text), temp, temp.GetLength());
TRACE("%s\n", text);

New window

Windows are managed by creating a class, and various functions are managed by rewriting (initialization, mapping)

Create a child window: add a class (inherited from Dialog)

Resource view->Dialog->Add resource

Creation of modal and non-modal windows

Advantages of dynamic creation: create it when used, without occupying resources in advance

When the creation time is too long, you can open a thread at the beginning to create it silently.

#include "CSonWnd.h"

CSonWnd dlg;
void CDlgDlg::OnBnClickedSonWnd()
{
    
    
	//CSonWnd dlg;
	//dlg.DoModal();
    //模态对话框,子窗口关闭后才能继续操作父窗口,代码会卡在这里

	if(dlg.m_hWnd==NULL)
		dlg.Create(IDD_DIG_EDY, this);
	dlg.ShowWindow(SW_SHOW);//SW_HIDE
	//非模态,因为不阻塞,要保证创建后不消失,就需要在全局进行声明
}

window size

button

protected:
	 CButton m_button;

void CSonWnd::OnBnClickedOk()
{
    
    
	if (m_button.m_hWnd == NULL)
		m_button.Create(_T("dynamic"), BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD, CRect(100, 100, 200, 150), this, 9999);
}

Edit box

Multi-line display: Behavior->multiline, want return, appearance->vertical scroll Set these three to true

Format input: Appearance->Lowercase/Uppercase/Number

Events: Input change checking (basic syntax of code), blocking keywords (expletives)

  • read
	CWnd* pEdit01 = GetDlgItem(IDC_EDIT_ONE);

	pEdit01->SetWindowText(_T("100"));
	SetDlgItemText(IDC_EDIT_ONE, _T("200"));

	CString strText;
	pEdit01->GetWindowText(strText);
	GetDlgItemText(IDC_EDIT_ONE, strText);

Override controls, escape button

Cbutton’s Zorder is higher

Ideas to adjust after mousemove and button position,

The failure is because the button Zorder is larger than the main window and mousemove will be captured but will not be processed, so the class needs to be overloaded to respond.

CRect curRect;
GetWindowRect(curRect);
curRect.bottom; curRect.top;curRect.Width()

Class Wizard->Add Class (upper right corner)->MFC Class->The parent class is CButton (used to replace the original CButton class)

Then add the member function mousemove to respond

void BTN::OnMouseMove(UINT nFlags, CPoint point)
{
    
    
	ShowWindow(SW_HIDE);
	Other->ShowWindow(SW_SHOW);
    
	CButton::OnMouseMove(nFlags, point);
}

property page

Dlg->button->sheet->page

Related controls

  • radio button

ctrl+D viewing order (the default is creation order, Tab order), which can be changed by clicking

The first radio button needs to be set to the group attribute

  • checkbox(checked)

When adding variables, you can add an array instead of adding them one by one.

memset(m_skill, 0, sizeof(m_skill));

  • List box (list) class view->override OnInitDialog

You can turn off the sorting in the properties, because the Chinese sorting rules are a bit strange.

BOOL PROP_01::OnInitDialog()
{
    
    
	CPropertyPage::OnInitDialog();

	// TODO:  在此添加额外的初始化
    //两种添加方式
	CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST1);
	if (pListBox) {
    
    
		pListBox->AddString(_T("ALI"));
		pListBox->AddString(_T("HUAWEI"));
		pListBox->AddString(_T("JD"));
         m_com.AddString(_T("APPLE"));
	}


	return TRUE; 
}
  • Drop-down box (Combo) Properties->Behavior->Data->Separate with semicolons

Multiple page switching

Create page

Resource view, New dialog box

Add MFC class to manage pages, inherited from CPropertyPage

The class name should be the same as the page name IDD_PAGE_01 should be PAGE_01

Switch page

Implement switching by creating an inherited class of CPropertySheet

.h

#include "PROP_01.h"
#include "PROP_02.h"
public:
	PROP_01 m_prop1;
	PROP_02 m_prop2;

.cpp

There are two constructors, both of which need to be added

AddPage(&m_prop1);
AddPage(&m_prop2);
  • Jump to multiple page switching

In fact, it can be made into an array, and the code will be more concise.

void CRunBTNDlg::OnBnClickedQueryBtn()
{
    
    
	CPropSheet dlg(_T("调查"), this);
	dlg.SetWizardMode();//wizard 向导 下一步上一步
	if (ID_WIZFINISH == dlg.DoModal())
	{
    
    //创建成功后,将数据返回到父窗口
        
		CString strMsg = _T("your lang: ");
        //单选
		switch (dlg.m_prop1.m_lang)
		{
    
    
		case 0:strMsg += "C++";break;
         case 1:strMsg += "Java";break;
		case 2:strMsg += "Python";break;
		}
        //多选
        CString strSkill[4]={
    
    _T("数据结构"),_T("计算机组成原理"),_T("操作系统"),_T("计算机网络")}
        for(int i=0;i<4;i++) 
            if(dlg.m_prop1.m_skill[i])
                strMsg += strSkill[i] + _T(",");
		MessageBox(strMsg);
	}
}
  • Sheet related button customization

Override OnSetActive() of each page class

BOOL PROP_01::OnSetActive()
{
    
    
    //第一页只需要next    //PSWIZB_BACK | PSWIZB_FINISH 用于中间页和最后一页
	((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);
	//去掉帮助按钮
    ((CPropertySheet*)GetParent())->GetDlgItem(IDHELP)->ShowWindow(SW_HIDE);
	return CPropertyPage::OnSetActive();
}
  • Check if selected
LRESULT PROP_01::OnWizardNext()//wizard向导,巫师
{
    
    
	UpdateData(TRUE);
    //TRUE表示将控件的值传到变量 FALSE相反
    //检查单选框
	if (m_lang == -1){
    
    
		MessageBox(_T("请选择开发语言"));
		return -1;
	}
    //检查复选框
    bool skillchoose = false;
    for(auto x : skill)
		skillchoose |= x;
    if(!skillchoose){
    
    
         MessageBox(_T("请选择技能"));
		return -1;
    }
    //检查列表框
    if (m_company == ""){
    
    
         MessageBox(_T("请选择公司"));
		return -1;
    }
	return CPropertyPage::OnWizardNext();
}

Other commonly used controls

list box

When set to multi-select, add controls and response functions

void PROP_01::OnBnClickedOk()
{
    
    
	CString strText;
	int total = m_com.GetSelCount();
	if (total == 0) {
    
    MessageBox(_T("没有选择公司"));return;}
	else {
    
    
		int* index = new int[total];
		m_com.GetSelItems(total, index);
		CString strTemp;
		for (int i = 0; i < total; i++)
		{
    
    
			m_com.GetText(index[i], strTemp);
			strText += strTemp + _T(" ");
		}
		delete[] index;
		MessageBox(strText);
	}
}

drop down box

Added items: Properties->Behavior->Data->separated by semicolon

Is a partial collection of edit boxes and list boxes

m_simple.GetCurSel();
GetLBText();//LB ListBox

progress bar

Add a control and use a timer to regularly obtain background data. The i and j of the loop are mapped to (0,100)

int m_pro_pos;//全局的进度,用来存放i,j的映射

//初始化
{
    
    //m_progress为控件名,设置范围和定时器
m_progress.SetRange(0, 100);//默认范围为int,可设置为SetRange32
SetTimer(99, 500, NULL);//(ID,触发间隔,NULL),可以设多个定时器,触发间隔不低于30帧,误差小
}

void PROP_01::OnTimer(UINT_PTR nIDEvent)
{
    
    //添加消息中的timer
	if (nIDEvent == 99)
		m_progress.SetPos(m_pro_pos);
	CPropertyPage::OnTimer(nIDEvent);
    if(m_pro_pos==100)KillTimer(99);
    /*if (nIDEvent == 99)//进度条自增
	{
		m_progress.SetPos(m_pro_pos);
		if (m_pro_pos < 100)m_pro_pos++;
	}*/
    //int lower,upper
    //m_progress.SetRange(lower, upper);
}

marquee The progress of the marquee loop, indicating that it is loading. After setting it to True, fill in the following code during initialization

m_progress.SetMarquee(TRUE, 50);

Report control

For window size and report style, CRECT or DWORD is obtained first, and then assigned back after setting.

mTab.GetClientRect(&rect);
Pages[i]->MoveWindow(&rect);

DWORD extStyle = ExeList.GetExtendedStyle();
ExeList.SetExtendedStyle(extStyle);

list control is similar to task manager

Appearance->always show selection/->true View->report single selection/multiple selection

Behavior->Sort/none

After adding the control CListCtrl m_list;, during initialization

	//背景色和文字背景
	m_list.SetBkColor(RGB(0,0,255));
	m_list.SetTextBkColor(RGB(0,0,255));
	//整体风格
	DWORD extStyle = m_list.GetExtendedStyle();
	//LVS  --  List View Style
	extStyle |= LVS_EX_FULLROWSELECT;//选择一行
	extStyle |= LVS_EX_GRIDLINES;//网格背景
	extStyle |= LVS_EX_CHECKBOXES;//勾选
	m_list.SetExtendedStyle(extStyle);
	//设置列
	//list view coloumn format
	m_list.InsertColumn(0, _T("序号"), LVCFMT_LEFT, 50);
	m_list.InsertColumn(1, _T("IP"), LVCFMT_LEFT, 150);
	m_list.InsertColumn(2, _T("ID"), LVCFMT_LEFT, 100);
	//添加行
	m_list.InsertItem(0, _T("0"));//(新建一行
	m_list.SetItemText(0, 1, _T("192.168.0.1"));//(插入某行的第几个
	m_list.SetItemText(0, 2, _T("2e4a4f"));

retrieve data

	int LineCount = m_list.GetItemCount();
	CHeaderCtrl* pHeader = m_list.GetHeaderCtrl();
	int ColumnCount = pHeader->GetItemCount();
	for (int i = 0; i < LineCount; i++) 
	{
    
    
		//获取选中状态
		if (m_list.GetCheck(i)) {
    
    TRACE("选中");}
		else TRACE("未选中");
		for (int j = 0; j < ColumnCount; j++)
		{
    
    
			CString temp = m_list.GetItemText(i, j);
			MessageBox(temp);
		}
	}

Get double click status

void CWndINJ::OnNMDblclkList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    
    //获取选中状态  NM : notification message  HDR : handler
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	*pResult = 0;
	//只有下面一句,前面是自动生成的
	int index = pNMItemActivate->iItem;
}

tree control

As shown in the file tree on the left

public:
	CTreeCtrl m_tree;
	CImageList m_icons;

//创建图像列表来管理图像
m_icons.Create(IDB_TREE, 32, 2, 0);
m_tree.SetImageList(&m_icons, TVSIL_NORMAL);

//文件的内容,句柄用以关联子结点
HTREEITEM hRoot = m_tree.InsertItem(_T("root"),0,1);
HTREEITEM hLeaf1 = m_tree.InsertItem(_T("leaf"),1,1,hRoot);

Tab control

Properties->Dynamic Layout->Resize Type->Both

Then add each tab dialog box, pay attention to set the border to None, Appearance->Style->child

Create a sub-window, because there are many sub-windows, encapsulate the process into a function

bool CGameHackerDlg::InstallPage(CDialogEx* wnd, int IDD_WND, CString&& _PageName)
{
    
    
	if (CurPage >= MAX_PAGE)return false;
	else
	{
    
    

		//用数组的方式显示窗口
		Pages[CurPage] = wnd;
		Pages[CurPage]->Create(IDD_WND);
		Pages[CurPage]->SetParent(this);
		//PageINJ.Create(IDD_PAGE_1, this);//有问题
		Pages[CurPage]->ShowWindow(false);

		//更改窗口的位置,防止切换页面时子窗口覆盖,(⊙﹏⊙)
		CRect rect;
		mTab.GetClientRect(&rect);
		rect.top += 48;
		rect.left += 6;
		Pages[CurPage]->MoveWindow(&rect);

		mTab.InsertItem(CurPage, _PageName);
		CurPage++;
		return true;
	}
}

Get newsmTab.GetCurSel()

void CGameHackerDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
    
    
	*pResult = 0;
	int n = mTab.GetCurSel();
	for (int i = 0; i < CurPage; i++)
		Pages[i]->ShowWindow(i == n);
}

Guess you like

Origin blog.csdn.net/killsime/article/details/135133755