1.初使用的简单代码
该程序包含两个代码 头文件mfc.h和mfc.cpp文件
头文件mfc.h
#pragma once
#include<afxwin.h>
class MyApp:public CWinApp//CWinApp应用程序类
{
public:
//程序入口
virtual BOOL InitInstance();
};
class MyFrame : public CFrameWnd//继承窗口框架类a
{
public:
MyFrame();
};
程序文件mfc.cpp
#define _CRT_SECURE_NO_WARNINGS
#include"mfc.h"
MyApp app;//全局应用程序对象
BOOL MyApp::InitInstance()
{
//创建窗口对象
MyFrame* frame = new MyFrame;
//显示和更新
frame->ShowWindow(SW_SHOWNORMAL);
frame->UpdateWindow();
m_pMainWnd = frame;//保存窗口的指针
return TRUE;
}
MyFrame::MyFrame()
{
Create(NULL, L"mfc");//创建窗口
}
代码解析
mfc需要包含的头文件 afxwin.h
自定义类MyApp,继承了cWinApp应用程序类,使用MyApp创建应用程序类对象,该对象有且仅有一个
在MyApp类中定义的函数 InitInstance 是整个应用程序的入口
自定义类MyFrame,继承了框架类CFrameWnd ,使用该类的构造函数创建了一个窗口,
Create函数的使用, Create(NULL, 标题名称)
使用MyFrame创建一个窗口对象
使用ShowWindow和UpdateWindow两个函数显示和更新
注意:在该程序中编译会出现错误,需要在 项目属性-> 高级-> MFC的使用中调成 在共享DLL中使用MFC
2.消息映射机制
消息映射声明和分界宏
DECLARE_MESSAGE_MAP | 声明将在类中使用消息映射来将消息映射到函数(必须在类声明中使用) |
BEGIN_MESSAGE_MAP | 开始消息映射的定义(必须在类实现中使用) |
BEGIN_TEMPLATE_MESSAGE_MAP | 开始在包含单个模板参数的类类型上定义消息映射 |
END_MESSAGE_MAP | 结束消息映射的定义(必须在类实现中使用) |
处理消息程序的宏
映射条目 | 函数原型 |
ON_WM_LBUTTONDBLCLK() | afx_msg void OnLButtonDblClk(UINT, CPoint) |
ON_WM_LBUTTONDOWN() | afx_msg void OnLButtonDown(UINT, CPoint); |
ON_WM_CHAR() | afx_msg voidOnChar(UINT, UINT, UINT); |
查看更多的映射条目可以查看该链接
https://learn.microsoft.com/zh-cn/cpp/mfc/reference/wm-message-handlers-a-c?view=msvc-170
使用的函数代码
class MyFrame : public CFrameWnd//继承窗口框架类a
{
public:
MyFrame();
//声明宏 提供消息映射机制
DECLARE_MESSAGE_MAP()
afx_msg void OnLButtonDown(UINT, CPoint);//鼠标左键点击的函数原型 ON_WM_LBUTTONDOWN()
afx_msg void OnChar(UINT, UINT, UINT);//键盘按下的函数原型 ON_WM_CHAR()
afx_msg void OnPaint();//绘图的函数原型 ON_WM_PAINT()
};
//分界宏
BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)
ON_WM_LBUTTONDOWN()//鼠标左键按下
ON_WM_CHAR()//键盘点击
ON_WM_PAINT()//绘图宏
//结束 消息映射机制
END_MESSAGE_MAP()
3.各个函数及类的解析
1.mfc中的字符串
在mfc中也有专属的字符串 CString,CString是一个类提供了许多函数对 CString 对象进行格式设置和分析,详细可查看该链接 https://learn.microsoft.com/zh-cn/cpp/mfc/reference/cstring-formatting-and-message-box-display?view=msvc-170
使用到的代码
CString str;
str.Format(L"x = %d y = %d", point.x, point.y);//格式化字符串
MessageBox(str);
4.字符集
多字节:表示一个字符对应一个字节
宽字节:表示一个字符对应多个字节
宽字符字符串长度统计:
//统计宽字符的字符串长度
wchar_t p[10] = TEXT("aaa");
int a = wcslen(p);
char*与CString之间的转换
//char*与CString之间的转换
//char*转CString
char str[10] = "aaa";
char* p1 = str;
CString cstr = CString(p1);
//CString 转 char*
CStringA temp;
temp = cstr;
char* pp = temp.GetBuffer();
宽字符的比较:
C++中字符串 string 容器的操作都与 str有关,比如 strchar,strstr…
但这都是对于ascll的字符串。
如果想操作宽字符串,把str换成wcs就可以,比如wcswcs 宽字符串比较函数
5.对话框的使用
一些控件:
Button按钮:设置了这个按钮可以绑定其它控件,使其点击时可以触发控件,当双击按钮时可以自动生成代码
Static Text控件:要控制该控件需要添加变量,要添加变量就需要修改他的ID,不能是以STATIC结尾
Edit Contrl控件:这个控件可以编辑内容,在属性里可以设置单行,多行,接收Enter,滚动条等等
Combo Box控件:这是一个下拉控件,在属性中找到 数据项可以加入数据,使用 ; 分割,默认排序修改为FALSE就不会排序,type类型改为 下拉列表 是不可以改变内容的
List Control控件:列表控件,该控件可以设置一个表格,在属性中的视图可以修改格式
Tree Control控件:树控件,在属性中可以设置一些风格
一些操作:
右击对话框可以添加类进行绑定
右击static控件可以添加变量
Edit Contrl控件有默认bug,需要在类视图中找到对话框类,然后右击属性,找到重写,添加 OnOk 功能,把里面的代码注释掉才可以按Enter不退出对话框
一些函数:
xx.SetWindowTextW(字符串):设置控件或者按钮的内容
xx.GetWindowTextW(字符串变量):获取控件或者按钮的内容
xx.EnableWindow(BOOL值):设置按钮的状态
xx.OnOk():退出对话框
xx.OnCancel():退出对话框
UpdateData(BOOL):为FALSE时,表示将变量内容同步到控件中,为TRUE时,表示将控件内容同步到变量中
1.模态对话框
定义:在一个主窗口中打开一个子窗口,当只有关闭子窗口时,才可以操作主窗口,这个子窗口即为模态对话框
代码实例
//模态对话框按钮点击事件
void C模态对话框Dlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
DlgExec dlg;
dlg.DoModal();//模态对话框弹出
}
2.非模态对话框
定义:在一个主窗口中打开一个子窗口,不需要关闭该子窗口也能能够控制主窗口,则该子窗口即为非模态对话框
代码示例
//非模态对话框按钮点击事件
void C模态对话框Dlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
//CDlgShow dlg;
//dlg.Create(IDD_SHOW);//非模态对话框创建
dlg.ShowWindow(SW_SHOWNORMAL);//显示模态对话框
}
3.Static Text(静态文本)控件添加图片
固定代码段:
//设置静态控件窗口风格为位图居中显示
n_pic.ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);
//通过路径获取bitmap句柄
#define HBMP(filepath, width, height) (HBITMAP)LoadImage(AfxGetInstanceHandle(), filepath, IMAGE_BITMAP, width, height, LR_LOADFR)
//获取静态控件的大小
CRect rect;
n_pic.GetWindowRect(rect);
//静态控件设置bitmap
n_pic.SetBitmap(HBMP(TEXT("./1.webp"), rect.Width(), rect.Height()));
4.Edit Control(编辑框)
给Edit Control编辑框控件添加变量时,可以设置添加变量的类型是控件或者是值,
如果设置为控件需要调用内部函数对编辑框进行内容编辑,如果设置的类型为值则可以直接使用等号进行设置内容
控件类型代码:
void CMy03EditTextDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
n_edit1.GetWindowTextW(str);//获取内容
n_edit2.SetWindowTextW(str);//设置内容
}
值类型代码:
void CMy03EditTextDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
//利用关联value的方式 设置和改变edit的内容
n_text1 = L"哈哈";
UpdateData(FALSE);//将变量内容 同步到控件中
}
5.Combo Box(下拉框)
函数:
xx.AddString(字符串):添加下拉框中的内容
xx.SetCurSel(索引):设置下拉框中默认的内容
xx.InsertString(索引,字符串):向下拉框中插入内容,索引表示插入的位置
xx.DeleteString(索引):删除下拉框中的内容,索引表示删除的位置
xx.GetLBText(索引,字符串):获取下拉框中的内容,索引表示获取的位置内容
代码示例:
//添加下拉内容
n_cbx.AddString(L"李白");
n_cbx.AddString(L"韩信");
n_cbx.AddString(L"马可");
n_cbx.AddString(L"刘禅");
n_cbx.SetCurSel(0);//设置下拉框的默认内容
n_cbx.InsertString(4, L"妲己");//插入下拉列表中
n_cbx.DeleteString(3);//删除指定的内容
CString str;
n_cbx.GetLBText(1, str);//获取下拉列表中的值
MessageBox(str);
6.List Control(列表控件)
使用到的函数:
1.xx.InsertColumn函数:给列表插入表头,只有view属性为Report报表模式才可以,函数原型
int InsertColumn(
int nCol,
const LVCOLUMN* pColumn);
int InsertColumn(
int nCol,
LPCTSTR lpszColumnHeading,
int nFormat = LVCFMT_LEFT,
int nWidth = -1,
int nSubItem = -1);
参数1 nCol:新列的索引
参数2 pColumn:包含新列属性的 LVCOLUMN 结构的地址 参数2 lpszColumnHeading:包含列标题的字符串的地址
参数3 nFormat:指定列的对齐方式的整数。 可以是以下值之一:LVCFMT_LEFT、LVCFMT_RIGHT 或 LVCFMT_CENTER
参数4 nWidth:列的宽度(以像素为单位)。 如果此参数为 -1,说明未设置列宽 参数5 nSubItem:与列相关联的子项的索引。 如果此参数为 -1,说明没有与列关联的子项
返回值:如果成功,返回下一列的索引;否则返回 -1
2.xx.InsertItem函数:在列表视图控件中插入项,有四个重载,函数原型
int InsertItem(const LVITEM* pItem);
int InsertItem(
int nItem,
LPCTSTR lpszItem);
int InsertItem(
int nItem,
LPCTSTR lpszItem,
int nImage);
int InsertItem(
UINT nMask,
int nItem,
LPCTSTR lpszItem,
UINT nState,
UINT nStateMask,
int nImage,
LPARAM lParam);
参数1 pItem:指向指定项的属性的 LVITEM 结构的指针
参数2 nItem:要插入的项的索引
参数3 lpszItem:包含项标签的字符串的地址;如果项为回调项,则为 LPSTR_TEXTCALLBACK
参数4 nImage:项的图像的索引;如果项为回调项,则为 I_IMAGECALLBACK
参数5 nMask:指定哪些作为参数传递的项属性有效
参数6 nState:指示项的状态、状态图像和覆盖图像
参数7 nStateMask:指示将检索或修改状态成员的哪些位
参数8 lparam:与项关联的 32 位(如果是为 x64 执行编译,则为 64 位)应用程序特定的值
3.xx.SetItemText函数:更改列表视图项或子项的文本,函数原型
BOOL SetItemText(
int nItem,
int nSubItem,
LPCTSTR lpszText);
参数1 nItem:要设置文本的项的索引
参数2 nSubItem:子项的索引;若要设置项标签,则为零
参数3 lpszText:指向包含新项文本的字符串的指针
返回值:如果成功,则不为零,否则为零
4.xx.SetExtendedStyle函数:设置列表视图控件当前的扩展样式,函数原型
DWORD SetExtendedStyle(DWORD dwNewStyle);
参数:要由列表视图控件使用的扩展样式的组合
返回值:列表视图控件使用的以前的扩展样式的组合
代码示例:
CString str[] = { L"姓名", L"性别", L"年龄" };
for (int i = 0; i < 3; i++)
{
n_list.InsertColumn(i, str[i], LVCFMT_LEFT, 100);//给列表插入表头
}
n_list.InsertItem(0, L"张三");//插入正文,第一行插入
n_list.SetItemText(0, 1, L"男");//在同一行插入第二列数据
n_list.SetItemText(0, 2, L"23");//在同一行插入第三列数据
//设置属性 整行选中状态 显示网格
n_list.SetExtendedStyle(n_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
7.Tree Control(树控件)
一些函数:
1.xx.SetImageList函数:调用此函数,可设置树视图控件的普通或状态图像列表(也就是把图标资源和树控件绑定),并使用新图像重新绘制控件,函数原型
CImageList* SetImageList(
CImageList* pImageList,
int nImageListType);
参数1 pImageList:指向要分配的图像列表的指针。 如果 pImageList 为 NULL,则从树视图控件中删除所有图像
参数2 nImageListType:要检索的图像列表的类型,值可以是TVSIL_NORMAL和VSIL_STATE
详细在这里➡https://learn.microsoft.com/zh-cn/cpp/mfc/reference/ctreectrl-class?view=msvc-170#setimagelist
2.xx.InsertItem函数:调用此函数以在树视图控件中插入新项,详细在这里➡https://learn.microsoft.com/zh-cn/cpp/mfc/reference/ctreectrl-class?view=msvc-170#insertitem
3.xx.SelectItem函数:调用此函数以选择给定的树视图项,详细在这里➡
https://learn.microsoft.com/zh-cn/cpp/mfc/reference/ctreectrl-class?view=msvc-170#selectitem
代码示例:
//树控件使用
//准备HICON图标
HICON icons[2];
icons[0] = AfxGetApp()->LoadIconW(IDI_ICON1);
icons[1] = AfxGetApp()->LoadIconW(IDI_ICON2);
//1.设置图标
//CImageList list;
list.Create(30, 30, ILC_COLOR32, 2, 2);//创建图片集合
for (int i = 0; i < 2; i++)
{
list.Add(icons[i]);//添加具体的图片
}
n_tree.SetImageList(&list, TVSIL_NORMAL);//
//设置节点
HTREEITEM root = n_tree.InsertItem(L"根节点", 0, 0, NULL);
HTREEITEM parent = n_tree.InsertItem(L"父节点", 1, 1, root);
HTREEITEM sub1 = n_tree.InsertItem(L"字节点1", 2, 2, parent);
HTREEITEM sub2 = n_tree.InsertItem(L"子节点2", 3, 3, parent);
//设置默认项
n_tree.SelectItem(sub1);
6.项目中的问题
项目基于mfc下单个文档编写。
1.在mfc项目中添加mfc类:右键项目->添加->新建项目->选中mfc类
CTreeView基类需要包含的头文件 afxcview.h
2.切分窗口:
CSplitterWnd 创建一个切分窗口类的对象 m_splite
需要重写OnCreateClient函数,为框架创建客户端窗口,在 OnCreate 执行过程中由框架调用,返回TRUE表示自己拆分,在该函数中使用m_splite对象调用函数对窗口进行拆分,函数原型:
virtual BOOL OnCreateClient(
LPCREATESTRUCT lpcs,
CCreateContext* pContext);
m_splite.CreateStatic函数:对窗口进行拆分,函数详情➡https://learn.microsoft.com/zh-cn/cpp/mfc/reference/csplitterwnd-class?view=msvc-170#createstatic
函数原型:
virtual BOOL CreateStatic(
CWnd* pParentWnd,
int nRows,
int nCols,
DWORD dwStyle = WS_CHILD | WS_VISIBLE,
UINT nID = AFX_IDW_PANE_FIRST);
参数 1 pParantWnd:拆分器窗口的父框架窗口
参数2 nRows:行数。 此值不得超过 16
参数3 nCols:列数。 此值不得超过 16
参数4 dwStyle:指定窗口样式
参数5 nID:窗口的子窗口的 ID。 ID 可以是 AFX_IDW_PANE_FIRST,除非拆分器窗口嵌套在另一个拆分器窗口中
m_splite.CreateView函数:指定拆分出来的窗口的类型,函数详情➡https://learn.microsoft.com/zh-cn/cpp/mfc/reference/csplitterwnd-class?view=msvc-170#createview
函数原型:
virtual BOOL CreateView(
int row,
int col,
CRuntimeClass* pViewClass,
SIZE sizeInit,
CCreateContext* pContext);
参数1 row:指定要在其中放置新视图的拆分器窗口行
参数2 col:指定要在其中放置新视图的拆分器窗口列 参数3 pViewClass:指定新视图的 CRuntimeClass
参数4 sizeInit:指定新视图的初始大小 参数5 pContext:指向用于创建视图的创建上下文的指针(通常是 pContext 传递到父框架的被替代的 CFrameWnd::OnCreateClient 成员函数,其中正在创建拆分器窗口)
返回值:如果成功,则不为 0;否则为 0
代码示例:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: 在此添加专用代码和/或调用基类
//return CFrameWnd::OnCreateClient(lpcs, pContext);//默认拆分
//拆分成1行2列
m_splite.CreateStatic(this, 1, 2);
//左侧和右侧具体的显示内容
m_splite.CreateView(0, 0, RUNTIME_CLASS(CSelectView), CSize(200, 500), pContext);
m_splite.CreateView(0, 1, RUNTIME_CLASS(CDisplayView), CSize(600, 500), pContext);
return TRUE;//表示自己拆分
}
3.界面挂载
使用到了 CCreateContext 结构,是没有基类的,创建窗口时,
此结构中的值提供用于将文档组件连接到其数据视图的信息。 仅当重写部分创建过程时才需使用 CCreateContext
CCreateContext 结构包含指向文档、框架窗口、视图和文档模板的指针。 它还包含指向 CRuntimeClass(用于标识要创建的视图类型)的指针。 运行时类信息和当前文档指针用于动态创建新视图
使用的成员函数:
CCreateContext结构中的成员函数 | ||
函数 | 类型 | 用途 |
m_pNewViewClass | CRuntimeClass* | 要创建的新视图的 CRuntimeClass |
m_pCurrentFrame | CFrameWnd* | 用于对其他框架窗口进行建模的框架窗口,如在文档中创建第二个框架窗口 |
m_pLastView | CView* | 用于对其他视图进行建模的原始视图,如创建拆分器窗口视图或在文档中创建第二个视图 |
CSplitterWnd类中的函数 | ||
DeleteView | 从拆分器窗口中删除视图 | |
CreateView | 调用,用于在拆分器窗口中创建窗格 | |
GetPane | 返回指定行和列的窗格 | |
RecalcLayout | 调整行或列大小后调用,以重新显示拆分器窗口 | |
SetActivePane | 将窗格设置为框架中的活动窗格 |
以下代码是把需要的界面挂载上去:
CCreateContext Context;
Context.m_pNewViewClass = RUNTIME_CLASS(CUserDlg);
Context.m_pCurrentFrame = this;
Context.m_pLastView = (CFormView*)m_splite.GetPane(0, 1);
m_splite.DeleteView(0, 1);
m_splite.CreateView(0, 1, RUNTIME_CLASS(CUserDlg), CSize(600, 500), &Context);
CUserDlg* pNewView = (CUserDlg*)m_splite.GetPane(0, 1);
m_splite.RecalcLayout();
pNewView->OnInitialUpdate();
m_splite.SetActivePane(0, 1);
4.发送自定义的函数信号
//PostMessage:将消息放入窗口的消息队列中,然后返回且不等待相应的窗口处理消息
//需要包含框架类头文件#include "MainFrm.h"
//CWnd::PostMessage 将一个消息放入窗口的消息队列
//AfxGetMainWnd():框架窗口对象的指针
//AfxGetMainWnd()->GetSafeHwnd():获取返回窗口的句柄,CWnd::GetSafeHwnd
//NM_A:发送自定义消息
//(WPARAM)NM_A:指定了附加的消息信息
//(LPARAM)0:指定了附加的消息信息,此参数这里没有意义
::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_A, (WPARAM)NM_A, (LPARAM)0);//把消息发出去
发送出去的消息会给到CMainFrame类中的自定义消息处理函数中