1 新建项目

1.1 根据向导创建项目

首先,新建MFC项目(SaleSystem),基于单文档,MFC标准项目,同时,去掉工具栏:
20 MFC - 案例总结_# MFC
20 MFC - 案例总结_# MFC_02
20 MFC - 案例总结_# MFC_03

1.2 添加预处理指令

由于微软在VS2013中不建议再使用C/C++的传统库函数scanf,strcpy,sprintf等,所以直接使用这些库函数会提示C4996错误。

VS建议采用带_s的函数,如scanf_s、strcpy_s,但这些并不是标准C/C++函数。要想继续使用此函数,需要添加 _CRT_SECURE_NO_WARNINGS这个预定义。

在项目 -> 属性 -> C/C+±>预处理器 -> 预处理器定中添加 _CRT_SECURE_NO_WARNINGS:

20 MFC - 案例总结_# MFC_04

1.3 设置窗口属性

  1. 设置图标
    打开资源视图,添加本地ICO图标,在res文件夹中添加我们提前准备的图标资源:
    20 MFC - 案例总结_# MFC_0520 MFC - 案例总结_# MFC_06
    在资源的属性中修改ID(IDI_ICON_WIN):
    20 MFC - 案例总结_# MFC_07
    在CMainFrame的 OnCreate()中添加如下代码:
    20 MFC - 案例总结_# MFC_08
//设置图标,IDI_ICON_WIN为图标资源ID,此为WINAPI函数
SetClassLong(m_hWnd, GCL_HICON, (LONG)AfxGetApp()->LoadIconW(IDI_ICON_WIN));
  1. 设置窗口大小和居中显示
    还是在CMainFrame的OnCreate()中接着写代码:
//设置窗口的位置和大小:CWnd::MoveWindow
//0, 0, 起点坐标x和y
//800, 500, 窗口宽度和高度
MoveWindow(0, 0, 800, 500);

//将窗口移动到屏幕中央,CWnd::CenterWindow
CenterWindow();
  1. 设置窗口标题

在CSaleSystemDoc文档类中的OnNewDocument()函数中添加如下代码:

20 MFC - 案例总结_# MFC_09

//设置窗口标题,CDocument::SetTitle
SetTitle(TEXT("销售管理系统"));

程序运行效果图如下:
20 MFC - 案例总结_# MFC_10

2 文件处理

2.1 文件内容格式

登陆用户信息:
20 MFC - 案例总结_# MFC_11
商品信息:
20 MFC - 案例总结_# MFC_12

2.2 设计文件处理类CInfoFile

  1. 添加文件处理类CInfoFile
    20 MFC - 案例总结_# MFC_13
    20 MFC - 案例总结_# MFC_14
    20 MFC - 案例总结_# MFC_15
    20 MFC - 案例总结_# MFC_16
  2. 头文件(InfoFile.h)的设计
    定义两个配置文件路径宏:
#define _F_LOGIN "./login.ini"
#define _F_STOCK "./stock.txt"

添加文件信息结构体,具体如下:

struct msg
{
	int id;		//商品id
	string name;	//商品名,别忘包含相应头文件
	int price;	//商品价格
	int num;	//商品个数
};

商品很多,而且要经常添加删除,可以考虑用链表来存储,所以,在成员变量中添加list类型的成员变量:

list<msg> ls;	//存储商品容器,别忘包含相应头文件
int num;	//用来记录商品个数

项目中需要读写的文件有两种,用户信息配置文件和商品信息文件。具体 API 接口如下:

//读取登陆信息
void ReadLogin(CString &name, CString &pwd);

//修改密码
void WritePwd(char* name, char* pwd);

// 读取商品数据
void ReadDocline();

//商品写入文件
void WirteDocline();

//添加新商品
void Addline(CString name, int num, int price);

3 登陆对话框

3.1 ui设计

1)添加对话框资源(ID修改为DIALOG_LOGIN),添加所需控件:
20 MFC - 案例总结_# MFC_17
20 MFC - 案例总结_# MFC_18
2)选中对话框 -> 右击 -> 添加类 -> 类名:CLoginDlg
20 MFC - 案例总结_# MFC_19
20 MFC - 案例总结_# MFC_20
3)根据需求,控件关联所需变量
20 MFC - 案例总结_# MFC_21
用户名编辑区关联CString m_user,密码登陆框关联CString m_pwd。

3.2 功能实现

1)在对话框类中,重写 OnInitDialog 函数,进行初始化,设置一些默认登录信息。
20 MFC - 案例总结_# MFC_22
20 MFC - 案例总结_# MFC_23

m_user = TEXT("斧头帮帮主");	//用户名
m_pwd = TEXT("123456");//密码
UpdateData(FALSE); //内容更新到对应的控件

2)登陆窗口的创建

在应用程序类CSaleSystemApp的InitInstance() 里面的APP 创建之前创建登陆对话框:
20 MFC - 案例总结_# MFC_24

CLoginDlg dlg;	//创建登陆对话框,需要头文件#include "LoginDlg.h"
dlg.DoModal();	//以模态方式运行

3)登陆按钮功能实现

//登陆按钮处理函数
void CLoginDlg::OnBnClickedButton1()
{
	// TODO:  在此添加控件通知处理程序代码

	UpdateData(TRUE); //更新控件的数据到对应的变量

	CInfoFile file; //创建操作文件类对象,需要头文件#include "InfoFile.h" 
	CString user, pwd;

	//读取配置文件,获取用户名密码,参数为引用传递
	file.ReadLogin(user, pwd);

	if (m_user == user)//用户名相等
	{
		if (m_pwd != pwd)
		{
			MessageBox(_T("密码错误"));
			m_user.Empty(); //清空
			m_pwd.Empty();
		}
		else
		{
			CDialogEx::OnOK();
		}
	}
	else
	{
		MessageBox(_T("用户名不存在"));
		m_user.Empty();
		m_pwd.Empty();
	}
}

4)取消按钮功能实现

//取消按钮功能实现
void CLoginDlg::OnBnClickedButton2()
{
	// TODO:  在此添加控件通知处理程序代码
	exit(0);	//结束整个程序
}

5)右上角关闭按钮功能实现

选中对话框模板 -> 右击 -> 属性 -> 消息 -> WM_CLOSE
20 MFC - 案例总结_# MFC_25

//关闭按钮
void CLoginDlg::OnClose()
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	exit(0);	//结束整个程序

	CDialogEx::OnClose();
}

6)编辑区回车键关闭对话框问题解决
20 MFC - 案例总结_# MFC_26
20 MFC - 案例总结_# MFC_27

4 静态拆分窗口

4.1 自定义MFC视图类

自定义两个类:CSelectView和CDispalyView(它的基类必须是视图类)。

CSelectView继承于CTreeView,CDispalyView继承于CFormView。
20 MFC - 案例总结_# MFC_28
20 MFC - 案例总结_# MFC_29
20 MFC - 案例总结_# MFC_30
20 MFC - 案例总结_# MFC_31
20 MFC - 案例总结_# MFC_32

4.2 通过CSplitterWnd类拆分窗口

1)CMainFrame类中,声明CSplitterWnd类型的对象:

20 MFC - 案例总结_# MFC_33

private:
	CSplitterWnd m_spliter; // 切分窗口类对象
2)重写框架类CMainFrame的OnCreateClient函数

20 MFC - 案例总结_# MFC_34
把OnCreateClient()函数的返回值改为Return TRUE:
20 MFC - 案例总结_# MFC_35
静态拆分实现代码如下:20 MFC - 案例总结_# MFC_36

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
	// TODO:  在此添加专用代码和/或调用基类

	// 静态拆分窗口,1行2列,CSplitterWnd::CreateStatic
	m_spliter.CreateStatic(this, 1, 2);

	// 创建视图:CSplitterWnd::CreateView
	//0, 0 : 放在第0行第0列的位置
	//RUNTIME_CLASS(CSelectView) :需要头文件#include "SelectView.h", CSelectView在SelectView.h中声明
	// CSize(250, 500):指定视图宽度和高度
	//pContext : 为OnCreateClient()最后一个形参
	m_spliter.CreateView(0, 0, RUNTIME_CLASS(CSelectView), CSize(200, 500), pContext);

	//0, 1: 放在第0行第1列的位置
	//CDispalyView,需要头文件#include "DispalyView.h"
	m_spliter.CreateView(0, 1, RUNTIME_CLASS(CDispalyView), CSize(600, 500), pContext);

	//return CFrameWnd::OnCreateClient(lpcs, pContext);
	return TRUE;
}

程序运行效果图如下:
20 MFC - 案例总结_# MFC_37

5 树视图功能实现

5.1 添加功能节点

1)加载图标资源

20 MFC - 案例总结_# MFC_38
20 MFC - 案例总结_# MFC_39
图标资源ID改为:IDI_ICON_RE20 MFC - 案例总结_# MFC_40

2)CSelectView类中声明相应变量:

20 MFC - 案例总结_# MFC_41

	CTreeCtrl *m_treeCtrl;	//树控件
	CImageList m_imageList;	//图标列表
3)重写CSelectView的OnInitUpdate函数

20 MFC - 案例总结_# MFC_42

void CSelectView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();

	// TODO:  在此添加专用代码和/或调用基类
}
4)在CSelectView的OnInitUpdate函数中,完成初始化功能
void CSelectView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();

	// TODO:  在此添加专用代码和/或调用基类

	//图标资源的加载 CWinApp::LoadIcon
//IDI_ICON_RE为图标资源ID
	HICON icon = AfxGetApp()->LoadIconW(IDI_ICON_RE); 

	//图片列表的创建 CImageList::Create
	//30, 30:指定图标的宽度和高度
	//ILC_COLOR32:图标格式
	//1, 1:有多少图标就写多少
	m_imageList.Create(30, 30, ILC_COLOR32, 1, 1);

	//图片列表追加图标 CImageList::Add
	m_imageList.Add(icon);

	//获取数视图中的树控件 CTreeView::GetTreeCtrl
	m_treeCtrl = &GetTreeCtrl();

	//数控件设置图片列表 CTreeCtrl::SetImageList
	m_treeCtrl->SetImageList(&m_imageList, TVSIL_NORMAL);

	//树控件设置节点 CTreeCtrl::InsertItem
	m_treeCtrl->InsertItem(TEXT("个人信息"), 0, 0, NULL);
	m_treeCtrl->InsertItem(TEXT("销售管理"), 0, 0, NULL);
	m_treeCtrl->InsertItem(TEXT("库存信息"), 0, 0, NULL);
	m_treeCtrl->InsertItem(TEXT("库存添加"), 0, 0, NULL);
	m_treeCtrl->InsertItem(TEXT("库存删除"), 0, 0, NULL);
}

程序运行效果图如下:
20 MFC - 案例总结_# MFC_43

5.2 功能节点相应消息处理

20 MFC - 案例总结_# MFC_44

void CSelectView::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	// TODO:  在此添加控件通知处理程序代码
	*pResult = 0;
}

在上面函数,实现获取当前节点选中内容:

void CSelectView::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	// TODO:  在此添加控件通知处理程序代码
	*pResult = 0;

	//获取当前节点选中项目 CTreeCtrl::GetSelectedItem
	HTREEITEM item = m_treeCtrl->GetSelectedItem();

	//获取选中项的文本内容 CTreeCtrl::GetItemText
	CString str = m_treeCtrl->GetItemText(item);
	//MessageBox(str);

	if (str == TEXT("个人信息"))
	{
	}
	else if (str == TEXT("销售管理"))
	{
	}
	else if (str == TEXT("库存信息"))
	{
	}
	else if (str == TEXT("库存增加"))
	{
	}
	else if (str == TEXT("库存删除"))
	{
	}
}

6 个人信息管理窗口

6.1 ui设计

1)添加对话框资源(ID修改为DIALOG_USER),添加所需控件:

20 MFC - 案例总结_# MFC_45
在窗口属性中,Border改为None,Style改为Child:
20 MFC - 案例总结_# MFC_46
20 MFC - 案例总结_# MFC_47

2)选中对话框 -> 右击 -> 添加类 -> 类名:CUserDlg,基类选择CFormView

20 MFC - 案例总结_# MFC_48

3)根据需求,控件关联所需变量

身份编辑区关联CString m_user,用户名编辑框关联CString m_name,
新密码编辑框关联CString m_newPwd,确定密码编辑框关联CString m_surePwd。
20 MFC - 案例总结_# MFC_49

6.2 功能实现

1)在对话框类中,重写 OnInitDialog 函数,进行初始化。

20 MFC - 案例总结_# MFC_50

void CUserDlg::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();

	// TODO:  在此添加专用代码和/或调用基类
}

void CUserDlg::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();

	// TODO:  在此添加专用代码和/或调用基类

	CInfoFile file;	//需要头文件#include "InfoFile.h"
	CString name, pwd;
	file.ReadLogin(name, pwd); //读取文件的用户名和密码

	//初始化个人信息
	m_user = TEXT("销售员");	//身份
	m_name = name;	//用户名

	UpdateData(FALSE); //把数据更新到控件上
}

2)确定修改密码按钮功能实现

void CUserDlg::OnBnClickedButton1()
{
	// TODO:  在此添加控件通知处理程序代码

	UpdateData(TRUE);//更新控件内容到对应的变量中

	if (m_newPwd.IsEmpty() || m_surePwd.IsEmpty())
	{
		MessageBox(TEXT("输入密码不能为空"));
		return;
	}

	if (m_newPwd != m_surePwd)
	{
		MessageBox(TEXT("输入密码和确定密码不相等"));
		return;
	}

	CInfoFile file;	//需要头文件#include "InfoFile.h"
	CString name, pwd;
	file.ReadLogin(name, pwd); //读取文件的用户名和密码

	if (m_surePwd == pwd)
	{
		MessageBox(TEXT("输入密码和旧密码相等"));
		return;
	}

	//把用户名和密码的CString类型转为char *
	char *tmpName, *tmpPwd;
	//用户名
	CStringA tmp1;
	tmp1 = name;
	tmpName = tmp1.GetBuffer();
	//密码
	CStringA tmp2;
	tmp2 = m_surePwd;
	tmpPwd = tmp2.GetBuffer();

	file.WritePwd(tmpName, tmpPwd); //修改密码

	MessageBox(TEXT("密码修改成功"));

	//输入框内容清空
	m_surePwd.Empty();
	m_newPwd.Empty();
	UpdateData(FALSE); //把数据更新到控件上
}

3)取消按钮功能实现

void CUserDlg::OnBnClickedButton3()
{
	// TODO:  在此添加控件通知处理程序代码

	//输入框内容清空
	m_surePwd.Empty();
	m_newPwd.Empty();
	UpdateData(FALSE); //把数据更新到控件上
}

7 界面挂载

7.1 自定义信息发送

1)在CMainFrame 框架类中,添加自定义消息宏

20 MFC - 案例总结_# MFC_51

//WM_USER 是用户自定义消息的一个起始值
//WM_USER+100是为了区分系统消息和用户消息,避免冲突
#define NM_A	(WM_USER + 100)
#define NM_B	(WM_USER + 101)
#define NM_C	(WM_USER + 102)
#define NM_D	(WM_USER + 103)
#define NM_E	(WM_USER + 104)

2)在CMainFrame框架类中添加自定义消息处理函数:

20 MFC - 案例总结_# MFC_52

//自定义消息处理函数
afx_msg LRESULT OnMyChange(WPARAM wParam, LPARAM lParam);

3)对应的.cpp定义其函数

LRESULT CMainFrame::OnMyChange(WPARAM wParam, LPARAM lParam)
{

}

4)在CMainFrame框架类BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加自定义消息入口,与自定义消息处理函数绑定。

20 MFC - 案例总结_# MFC_53

//ON_MESSAGE响应的是自定义消息
//产生NM_X消息,自动调用OnMyChange函数
ON_MESSAGE(NM_A, OnMyChange)
ON_MESSAGE(NM_B, OnMyChange)
ON_MESSAGE(NM_C, OnMyChange)
ON_MESSAGE(NM_D, OnMyChange)
ON_MESSAGE(NM_E, OnMyChange)

5)发送自定义信号

在CSelectView的OnTvnSelchanged函数中,发送自定义信号:
20 MFC - 案例总结_# MFC_54

if (str == TEXT("个人信息"))
{
	//需要包含框架类头文件#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);
}
else if (str == TEXT("销售管理"))
{
::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_B, (WPARAM)NM_B, (LPARAM)0);
}
else if (str == TEXT("库存信息"))
{
::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_C, (WPARAM)NM_C, (LPARAM)0);
}
else if (str == TEXT("库存添加"))
{
::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_D, (WPARAM)NM_D, (LPARAM)0);
}
else if (str == TEXT("库存删除"))
{
::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_E, (WPARAM)NM_E, (LPARAM)0);
}

7.2 自定义信息处理

在CMainFrame框架类OnMyChange函数中处理相应消息

LRESULT CMainFrame::OnMyChange(WPARAM wParam, LPARAM lParam)
{
	switch (wParam)
	{
	case NM_A:
		MessageBox(_T("NM_A"));
		break;
	case NM_B:
		MessageBox(_T("NM_B"));
		break;
	case NM_C:
		MessageBox(_T("NM_C"));
		break;
	case NM_D:
		MessageBox(_T("NM_D"));
		break;
	case NM_E:
		MessageBox(_T("NM_E"));
		break;
	default:
		MessageBox(_T("error"));
	}
	return 0;
}

7.3 界面挂载

如果是NM_A信号,则挂载CUserDlg窗口,后面界面的挂载以此类推。
20 MFC - 案例总结_# MFC_55

CCreateContext   Context;
switch (wParam)
{
case NM_A:
{
	//CUserDlg类需要包含头文件#include "UserDlg.h"
	Context.m_pNewViewClass = RUNTIME_CLASS(CUserDlg); 
	Context.m_pCurrentFrame = this;
	Context.m_pLastView = (CFormView *)m_spliter.GetPane(0, 1);
	m_spliter.DeleteView(0, 1);
	m_spliter.CreateView(0, 1, RUNTIME_CLASS(CUserDlg), CSize(600,500), &Context);
	CUserDlg *pNewView = (CUserDlg *)m_spliter.GetPane(0, 1);
	m_spliter.RecalcLayout();
	pNewView->OnInitialUpdate();
	m_spliter.SetActivePane(0, 1);
}
	break;
case NM_B:
//……………

程序运行效果如下:
20 MFC - 案例总结_# MFC_56

8 销售管理窗口

8.1 ui设计

1)添加对话框资源(ID修改为DIALOG_SELL),添加所需控件。
20 MFC - 案例总结_# MFC_57
在窗口属性中,Border改为None,Style改为Child:
20 MFC - 案例总结_# MFC_58
20 MFC - 案例总结_# MFC_59
2)选中对话框 -> 右击 -> 添加类 -> 类名:CSellDlg,基类选择CFormView
20 MFC - 案例总结_# MFC_60
3)根据需求,控件关联所需变量
商品名组合框关联CComboBox m_combo,单价编辑框关联int m_price,
个数编辑框关联int m_num,销售信息编辑框关联CString m_sellInfo。
20 MFC - 案例总结_# MFC_61

8.2 界面挂载

在CMainFrame类中OnMyChange函数,添加如下代码:

case NM_B:
	{
		//CSellDlg类需要包含头文件#include "SellDlg.h"
		Context.m_pNewViewClass = RUNTIME_CLASS(CSellDlg);
		Context.m_pCurrentFrame = this;
		Context.m_pLastView = (CFormView *)m_spliter.GetPane(0, 1);
		m_spliter.DeleteView(0, 1);
		m_spliter.CreateView(0, 1, RUNTIME_CLASS(CSellDlg), CSize(600, 0), &Context);
		CSellDlg *pNewView = (CSellDlg *)m_spliter.GetPane(0, 1);
		m_spliter.RecalcLayout();
		pNewView->OnInitialUpdate();
		m_spliter.SetActivePane(0, 1);
	}
		break;

程序运行效果图:
20 MFC - 案例总结_# MFC_62

8.3功能实现

1)在对话框类中,重写 OnInitDialog 函数,进行初始化。
20 MFC - 案例总结_# MFC_63

void CSellDlg::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();

	// TODO:  在此添加专用代码和/或调用基类

	//读取文件,获取商品名,给组合框添加字符串
	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		m_combo.AddString((CString)it->name.c_str());
	}

	file.ls.clear(); //清空list的内容

	//将第一个商品名设为默认选中项
	m_combo.SetCurSel(0);
}

2)处理组合框所需控制事件
20 MFC - 案例总结_# MFC_64

void CSellDlg::OnCbnSelchangeCombo1()
{
	// TODO:  在此添加控件通知处理程序代码

	CString text;
	//获取当前选中项
	int index = m_combo.GetCurSel();
	//获取当前内容
	m_combo.GetLBText(index, text);

	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		if (text == it->name.c_str())
		{
			m_price = it->price;
			m_num = 0;
			UpdateData(FALSE); //内容更新到对应的控件
		}
	}

	file.ls.clear(); //清空list的内容
}

3)购买按钮功能实现

void CSellDlg::OnBnClickedButton1()
{
	// TODO:  在此添加控件通知处理程序代码
	
	//获取控件上的内容,更新到对应关联的变量中
	UpdateData(TRUE);

	if (m_num == 0)
	{
		MessageBox(TEXT("个数不能为0"));
		return;
	}

	CString type;
	//获取当前选中项
	int index = m_combo.GetCurSel();
	//获取组合框当前内容
	m_combo.GetLBText(index, type);

	CString str;
	str.Format(_T("商品:%s \r\n单价:%d \r\n个数:%d \r\n总价:%d"), type, m_price, m_num, m_price*m_num);

	m_sellInfo = str; //销售信息
	UpdateData(FALSE);
	MessageBox(str);


	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		if (type == it->name.c_str())
		{
			it->num = it->num - m_num;
		}
	}
	file.WirteDocline(); //更新文件内容

	file.ls.clear(); //清空list的内容

	m_sellInfo.Empty();
	m_num = 0;
	UpdateData(FALSE); //更新到对应的控件
}

4)取消按钮功能实现

void CSellDlg::OnBnClickedButton3()
{
	// TODO:  在此添加控件通知处理程序代码

	m_combo.SetCurSel(0); //选择第0项目
	m_sellInfo = "";
	m_num = 0;
	OnCbnSelchangeCombo1();
}

9 库存信息窗口

9.1 ui设计

1)添加对话框资源(ID修改为DIALOG_INFO),添加所需控件。
20 MFC - 案例总结_# MFC_65
在窗口属性中,Border改为None,Style改为Child:
20 MFC - 案例总结_# MFC_66
View 属性为 Report(报表表模式):
20 MFC - 案例总结_# MFC_67
2)选中对话框 -> 右击 -> 添加类 -> 类名:CInfoDlg,基类选择CFormView
20 MFC - 案例总结_# MFC_68
3)根据需求,控件关联所需变量
列表控件关联CListCtrl m_list:
20 MFC - 案例总结_# MFC_69

9.2 界面挂载

在CMainFrame类中OnMyChange函数,添加如下代码:

case NM_C:
	{
		//CInfoDlg类需要包含头文件#include "InfoDlg.h"
		Context.m_pNewViewClass = RUNTIME_CLASS(CInfoDlg);
		Context.m_pCurrentFrame = this;
		Context.m_pLastView = (CFormView *)m_spliter.GetPane(0, 1);
		m_spliter.DeleteView(0, 1);
		m_spliter.CreateView(0, 1, RUNTIME_CLASS(CInfoDlg), CSize(600, 0), &Context);
		CInfoDlg *pNewView = (CInfoDlg *)m_spliter.GetPane(0, 1);
		m_spliter.RecalcLayout();
		pNewView->OnInitialUpdate();
		m_spliter.SetActivePane(0, 1);
	}
		break;

程序运行效果图:
20 MFC - 案例总结_# MFC_70

9.3功能实现

在对话框类中,重写 OnInitDialog 函数,进行商品信息初始化:
20 MFC - 案例总结_# MFC_71

void CInfoDlg::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();

	// TODO:  在此添加专用代码和/或调用基类
	// 设置扩展风格
	//LVS_EX_FULLROWSELECT选中整行,LVS_EX_GRIDLINES网格
	m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

	// 初始化表头
	CString field[] = { _T("商品ID"), _T("商品名称"), _T("商品价格"), _T("库存数量") };
	for (int i = 0; i < sizeof(field) / sizeof(field[0]); ++i)
	{
		m_list.InsertColumn(i, field[i], LVCFMT_CENTER, 90);
	}

	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息

	//添加数据
	int i = 0;
	CString str;
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		str.Format(_T("%d"), it->id);
		m_list.InsertItem(i, str);
		int column = 1;
		m_list.SetItemText(i, column++, (CString)it->name.c_str());
		str.Format(_T("%d"), it->price);
		m_list.SetItemText(i, column++, str);
		str.Format(_T("%d"), it->num);
		m_list.SetItemText(i, column++, str);
		i++;
	}

	
}

10 库存添加窗口

10.1 ui设计

1)添加对话框资源(ID修改为DIALOG_ADD),添加所需控件。
20 MFC - 案例总结_# MFC_72
在窗口属性中,Border改为None,Style改为Child:
20 MFC - 案例总结_# MFC_7320 MFC - 案例总结_# MFC_74
2)选中对话框 -> 右击 -> 添加类 -> 类名:CAddDlg,基类选择CFormView
20 MFC - 案例总结_# MFC_75
3)根据需求,控件关联所需变量
添加个数:
商品组合框关联CComboBox m_combo,单价编辑框关联int m_price1,
个数编辑框关联int m_num1。

添加新产品:
商品组合框关联CString m_name2,单价编辑框关联int m_price2,
个数编辑框关联int m_num2。
20 MFC - 案例总结_# MFC_76

10.2 界面挂载

在CMainFrame类中OnMyChange函数,添加如下代码:
20 MFC - 案例总结_# MFC_77

10.3功能实现

1)在对话框类中,重写 OnInitDialog 函数,进行商品信息初始化:
20 MFC - 案例总结_# MFC_78

void CAddDlg::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();

	// TODO:  在此添加专用代码和/或调用基类

	//读取文件,获取商品名,给组合框添加字符串
	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		m_combo.AddString((CString)it->name.c_str());
	}

	file.ls.clear(); //清空list的内容

	//将第一个商品名设为默认选中项
	m_combo.SetCurSel(0);
}

2)处理组合框所需控制事件
20 MFC - 案例总结_# MFC_79

void CAddDlg::OnCbnSelchangeCombo2()
{
	// TODO:  在此添加控件通知处理程序代码

	CString text;
	//获取当前选中项
	int index = m_combo.GetCurSel();
	//获取当前内容
	m_combo.GetLBText(index, text);

	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		if (text == it->name.c_str())
		{
			m_price1 = it->price;
			m_num1 = 0;
			UpdateData(FALSE); //内容更新到对应的控件
		}
	}

	file.ls.clear(); //清空list的内容
}

3)添加个数按钮实现

void CAddDlg::OnBnClickedButton1()
{
	// TODO:  在此添加控件通知处理程序代码

	//获取控件上的内容,更新到对应关联的变量中
	UpdateData(TRUE);

	if (m_num1 == 0)
	{
		MessageBox(TEXT("个数不能为0"));
		return;
	}

	CString type;
	//获取当前选中项
	int index = m_combo.GetCurSel();
	//获取组合框当前内容
	m_combo.GetLBText(index, type);

	CString str;
	str.Format(_T("添加了 商品:%s \r\n单价:%d \r\n个数:%d"), type, m_price1, m_num1);
	MessageBox(str);


	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		if (type == it->name.c_str())
		{
			it->num +=  m_num1;
		}
	}
	file.WirteDocline(); //更新文件内容

	file.ls.clear(); //清空list的内容

	m_num1 = 0;
	UpdateData(FALSE); //更新到对应的控件
}

4)添加个数取消按钮实现

void CAddDlg::OnBnClickedButton2()
{
	// TODO:  在此添加控件通知处理程序代码

	m_combo.SetCurSel(0);
	m_num1 = 0;
	OnCbnSelchangeCombo2();
}

5)添加新商品按钮实现

void CAddDlg::OnBnClickedButton4()
{
	// TODO:  在此添加控件通知处理程序代码

	UpdateData(TRUE); //获取控件内容

	if (m_num2 <= 0 || m_price2 <= 0 || m_name2.IsEmpty())
	{
		MessageBox(TEXT("输入信息有误"));
		return;
	}

	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	file.Addline(m_name2, m_num2, m_price2); //添加商品
	file.WirteDocline(); //写文件
	file.ls.clear(); //清空list的内容
	MessageBox(_T("添加成功"));

	m_name2.Empty();
	m_num2 = 0;
	m_price2 = 0;
	UpdateData(FALSE);
}

6)添加新商品取消按钮实现

void CAddDlg::OnBnClickedButton5()
{
	// TODO:  在此添加控件通知处理程序代码
	m_name2.Empty();
	m_num2 = 0;
	m_price2 = 0;
	UpdateData(FALSE);
}

11 库存删除窗口

11.1 ui设计

1)添加对话框资源(ID修改为DIALOG_DEL),添加所需控件。
20 MFC - 案例总结_# MFC_80
在窗口属性中,Border改为None,Style改为Child:
20 MFC - 案例总结_# MFC_81
20 MFC - 案例总结_# MFC_82
2)选中对话框 -> 右击 -> 添加类 -> 类名:CDelDlg,基类选择CFormView
20 MFC - 案例总结_# MFC_83
3)根据需求,控件关联所需变量
商品名组合框关联CComboBox m_combo,单价编辑框关联int m_price,
个数编辑框关联int m_num。
20 MFC - 案例总结_# MFC_84

11.2 界面挂载

在CMainFrame类中OnMyChange函数,添加如下代码:

case NM_E:
	{
		//CDelDlg类需要包含头文件#include "DelDlg.h"
		Context.m_pNewViewClass = RUNTIME_CLASS(CDelDlg);
		Context.m_pCurrentFrame = this;
		Context.m_pLastView = (CFormView *)m_spliter.GetPane(0, 1);
		m_spliter.DeleteView(0, 1);
		m_spliter.CreateView(0, 1, RUNTIME_CLASS(CDelDlg), CSize(600, 0), &Context);
		CDelDlg *pNewView = (CDelDlg *)m_spliter.GetPane(0, 1);
		m_spliter.RecalcLayout();
		pNewView->OnInitialUpdate();
		m_spliter.SetActivePane(0, 1);
	}
		break;

程序运行效果图:20 MFC - 案例总结_# MFC_85

11.3功能实现

1)在对话框类中,重写 OnInitDialog 函数,进行初始化。
20 MFC - 案例总结_# MFC_86

void CDelDlg::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();

	//读取文件,获取商品名,给组合框添加字符串
	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		m_combo.AddString((CString)it->name.c_str());
	}


	//将第一个商品名设为默认选中项
	m_combo.SetCurSel(0);
}

2)处理组合框所需控制事件
20 MFC - 案例总结_# MFC_87

void CDelDlg::OnCbnSelchangeCombo1()
{
	// TODO:  在此添加控件通知处理程序代码

	CString text;
	//获取当前选中项
	int index = m_combo.GetCurSel();
	//获取当前内容
	m_combo.GetLBText(index, text);

	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		if (text == it->name.c_str())
		{
			m_price = it->price;
			m_num = 0;
			UpdateData(FALSE); //内容更新到对应的控件
		}
	}

	
}

3)确定按钮功能实现

void CDelDlg::OnBnClickedButton1()
{
	// TODO:  在此添加控件通知处理程序代码

	//获取控件上的内容,更新到对应关联的变量中
	UpdateData(TRUE);

	if (m_num == 0)
	{
		MessageBox(TEXT("个数不能为0"));
		return;
	}

	CString type;
	//获取当前选中项
	int index = m_combo.GetCurSel();
	//获取组合框当前内容
	m_combo.GetLBText(index, type);

	CString str;
	str.Format(_T("删除商品:%s \r\n单价:%d \r\n个数:%d "), type, m_price, m_num);
	MessageBox(str);


	//需要包含#include "InfoFile.h"
	CInfoFile file;
	file.ReadDocline(); //读取商品信息
	for (list<msg>::iterator it = file.ls.begin(); it != file.ls.end(); it++)
	{
		if (type == it->name.c_str())
		{
			it->num = it->num - m_num;
		}
	}
	file.WirteDocline(); //更新文件内容

	

	m_num = 0;
	UpdateData(FALSE); //更新到对应的控件
}

4)取消按钮功能实现

void CDelDlg::OnBnClickedButton2()
{
	// TODO:  在此添加控件通知处理程序代码

	m_combo.SetCurSel(0); //选择第0项目
	m_num = 0;
	OnCbnSelchangeCombo1();
}

12 菜单栏

1)切换到资源视图的Menu,删除掉所有默认(帮助除外):20 MFC - 案例总结_# MFC_88
20 MFC - 案例总结_# MFC_89
2) 右键菜单栏项,添加事件处理程序,选择COMMAND 消息类型,添加至CMainFrame框架类中。
20 MFC - 案例总结_# MFC_90
20 MFC - 案例总结_# MFC_91
3)在事件处理函数中发送自定义信号,其它菜单操作类似。

//个人信息菜单
void CMainFrame::On32772()
{
	// TODO:  在此添加命令处理程序代码
::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_A, (WPARAM)NM_A, (LPARAM)0);
}