目录



由于现在VS不支持传统的scanf,strcpy,sprintf等,所以直接使用这些函数会提示C4996错误。
VS建议采用带有_s的函数,如scanf_s、strcpy_s,但是这些不是标准的C++函数,如果想要继续使用这些函数需要添加_CRT_SECURE_NO_WARNINGS这个预定义。
在项目->属性->c++预处理器->预处理器中添加_CRT_SECURE_NO_WARNINGS




导入成功后会出先在资源视图Icon里面




CMainFrame中的OnCreate函数的用途:
在MFC框架中,CMainFrame是主窗口的类,它是整个应用程序的核心。在CMainFrame的OnCreate函数中,通常会进行一些初始化操作,其中包括设置应用程序的图标。
应用程序的图标是应用程序的重要标志,它通常出现在窗口标题栏、任务栏和启动器等地方。
具体来说,在CMainFrame的OnCreate函数中,通常会进行以下步骤:
1、创建主窗口
通过调用CFrameWnd::Create函数来创建主窗口,并将窗口显示在屏幕上。
2、设置主窗口图标
通过调用CWnd::SetIcon函数来设置主窗口的图标。可以选择不同大小的图标,以适应不同的显示需要。
3、创建菜单和工具栏
根据设计需求,使用MFC提供的相关类来创建菜单和工具栏,并设置相应的功能和事件处理函数。
4、加载默认文档
根据设计需求,利用MFC的文档视图框架来加载应用程序的默认文档,并打开初始的文档窗口。
因此,在CMainFrame的OnCreate函数中设置应用程序的图标,是一个很自然和合理的选择。这样可以通过一次函数调用来完成这个任务,同时也可以与其他初始化操作相结合,使代码更加清晰和易于维护。
代码部分:

- //设置图标。IDI_ICON_WIN为图标资源ID
-
- // 在 CMainFrame::OnCreate 函数中设置窗口图标
-
- HICON hIcon = AfxGetApp()->LoadIconW(IDI_ICON_WIN);
- //SetIcon(hIcon, TRUE); // 设置大图标
- SetIcon(hIcon, FALSE); // 设置小图标
HICON代表图标资源句柄类型,
hIcon代表接收的窗口图标句柄,
AfxGetApp()->MFC全局函数(Afx开头)获取当前应用程序的指针
LoadIconW(ID)加载图标资源并且返回图标资源的句柄。

(左标题由操作系统管理在文档类)


-
- //设置左侧标题
- SetTitle(TEXT("销售管理系统"));

- //设置标题(右侧标题)
- SetTitle(TEXT("2023.10.17"));

至于为什么标题的设置还有图标的初始化会在这些函数中:
在 MFC 中,应用程序类(
CWinApp的派生类)负责应用程序的初始化和管理。当应用程序启动时,应用程序类的InitInstance函数被调用,可以在其中创建主窗口框架(CMainFrame)对象、文档模板(CDocTemplate)对象以及其他需要的资源。
主窗口框架类(
CMainFrame)是应用程序的主窗口,并且通常包含菜单栏、工具栏、状态栏等界面元素,通过CFrameWnd::OnCreate函数进行初始化。在OnCreate函数中,可以设置窗口的标题、图标、样式等属性。
文档类(
CDocument的派生类)负责管理应用程序的数据以及与数据相关的业务逻辑。每个文档类对应一个打开的文档实例,当打开新文档时,文档类的OnNewDocument函数会被调用。在OnNewDocument函数中,可以进行文档的初始化,包括设置标题、初始化数据等操作。

MoveWindow()函数前俩个参数代表坐标,后面俩个参数代表宽高。
CenterWindow()函数默认参数把窗口居中显示。
设置之后的窗口样式:



俩个文本文件可以直接读取,但是.h和.cpp文件必须得添加到现在的项目中


InfoFile.h
- #pragma once
-
- #include
- #include
- #include
- #include
- //#include
- //#include "stdafx.h"
-
- #define _F_LOGIN "./login.ini"//自定义宏_F_LOGIN代表打开login文件。
- #define _F_STOCK "./stock.txt"//自定义宏_F_STOCK代表打开stock文件。
-
- using namespace std;
-
- struct msg
- {
- int id; //商品id
- string name; //商品名
- int price; //商品价格
- int num; //商品个数
- };
-
- class CInfoFile
- {
- public:
- CInfoFile();
- ~CInfoFile();
-
- //读取登录信息
- void ReadLogin(CString &name, CString &pwd);
-
- //修改密码
- void WritePwd(char* name, char* pwd);
-
- //读取商品数据
- void ReadDocline();
-
- //商品写入文件
- void WriteDocline();
-
- //添加新商品
- void Addline(CString name, int num, int price);
-
- list
ls; //存储商品容器 - int num; //用来记录商品个数
-
- };
-
-
InfoFile.cpp
-
- #include "stdafx.h"
- #include "InfoFile.h"
-
-
- CInfoFile::CInfoFile()
- {
- }
-
- CInfoFile::~CInfoFile()
- {
- }
-
- //读取登录信息
- void CInfoFile::ReadLogin(CString &name, CString &pwd)
- {
- ifstream ifs; //创建文件输入对象
- ifs.open(_F_LOGIN);
- char buf[1024] = { 0 };
- if (!ifs.is_open()) {
- cout << "文件打开失败" << endl;
- }
-
- ifs.getline(buf, sizeof(buf)); //读取一行内容
- name = CString(buf); //将char* 转换为CString
-
- ifs.getline(buf, sizeof(buf)); //读取一行内容
- pwd = CString(buf); //将char* 转换为CString
-
- ifs.close(); //关闭文件
- }
-
- //修改密码
- void CInfoFile::WritePwd(char* name, char* pwd)
- {
- ofstream ofs; //创建文件输出对象
- ofs.open(_F_LOGIN); //打开文件
- if (!ofs.is_open())
- {
- cout << "文件打开失败" << endl;
- }
-
- ofs << name << endl; //name写入文件
- ofs << pwd << endl; //pwd写入文件
-
- ofs.close(); //关闭文件
- }
-
- //读取商品的信息
- void CInfoFile::ReadDocline()
- {
- ifstream ifs(_F_STOCK); //读取方式打开文件
-
- char buf[1024] = { 0 };
- num = 0; //初始化商品数量为0
- ls.clear();
- //取出表头
- ifs.getline(buf, sizeof(buf));
-
- while (!ifs.eof()) //没到文件结尾
- {
- msg tmp;
-
- ifs.getline(buf, sizeof(buf)); //读取一行
- num++; //商品数量加一
-
- //AfxMessageBox(CString(buf));
- char *sst = strtok(buf, "|"); //以"|"分隔
- if (sst != NULL)
- {
- tmp.id = atoi(sst); //商品id
- }
- else
- {
- break;
- }
-
- sst = strtok(NULL, "|");
- tmp.name = sst; //商品名称
-
- sst = strtok(NULL, "|");
- tmp.price = atoi(sst); //商品价格
-
- sst = strtok(NULL, "|");
- tmp.num = atoi(sst); //商品数目
-
- ls.push_back(tmp); //放在链表的后面
- }
-
- ifs.close(); //关闭文件
-
- }
-
-
- //商品写入文件
- void CInfoFile::WriteDocline()
- {
- ofstream ofs(_F_STOCK); //输出方式打开文件
- string bt = "商品ID|商品名|单价|库存";
-
- if (ls.size() > 0) //商品链表有内容才执行
- {
- ofs << bt << endl; //写入表头
-
- //通过迭代器取出链表内容,写入文件,以"|"分割,结尾加换行
- for (list
::iterator it = ls.begin(); it != ls.end(); it++) - {
- ofs << it->id << "|";
- ofs << it->name << "|";
- ofs << it->price << "|";
- ofs << it->num << endl;
- }
- }
- ofs.close();
-
- }
-
-
- //添加新商品
- //name:商品名称,num:库存,price:价格
- void CInfoFile::Addline(CString name, int num, int price)
- {
- msg tmp;
-
- if (ls.size() > 0)
- {
- //商品名称,库存,价格有效
- if (!name.IsEmpty() && num > 0 && price > 0)
- {
- tmp.id = ls.size() + 1; //id自动加1
- CStringA str;
- str = name; //CString 转CStringA
- tmp.name = str.GetBuffer();//CString 转为char *, 商品名称
- tmp.num = num; //库存
- tmp.price = price; //价格
-
- ls.push_back(tmp); //放在链表的后面
- }
- }
- }
(1)、功能测试


修改账号密码成功,弹出的新的账号密码。




密码的Edit Control属性设置为密码不可见





问题1:关闭选项,关闭进入主窗口
问题2:在edit里面按下回车直接进入主窗口


鼠标点击登录按钮事件
- void CLoginDlg::OnBnClickedButton1()
- {
- // TODO: 在此添加控件通知处理程序代码
-
- //登录按钮点击事件
- //控件中的内容同步到变量中,也就是密码同步到变量中
- UpdateData(TRUE);
- //1、判断俩个账号密码都不为空
- if (m_user.IsEmpty() || m_pwd.IsEmpty())
- {
- MessageBox(TEXT("输入内容不为空"));
-
- return;
- }
- //CInfoFile类可以获取账号密码
- CInfoFile file;
- CString pwd,name;
- file.ReadLogin(name, pwd);//用户名,密码
-
- if (name == m_user)//用户名一致
- {
- if (pwd == m_pwd)//密码一致
- {
- //关闭当前的对话框
- MessageBox(TEXT("登陆成功!"));
- CDialog::OnCancel();
- }
- else
- {
- MessageBox(TEXT("密码错误"));
- }
- }
- else
- {
- MessageBox(TEXT("用户名错误"));
- }
- }



默认直接有账号密码

- BOOL CLoginDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
-
- // TODO: 在此添加额外的初始化
-
- //默认登录信息
- CInfoFile file;
- CString name, pwd;
- file.ReadLogin(name, pwd);
-
- m_user = name;
- m_pwd = pwd;
- //同步到控件中
- UpdateData(FALSE);
-
-
- return TRUE; // return TRUE unless you set the focus to a control
- // 异常: OCX 属性页应返回 FALSE
- }


问题1 窗口关闭直接跳转主窗口
更改消息里面的WM_CLOSE函数


问题2回车不能跳转页面
重写OnOK()函数
OnOK()函数回关闭当前对话框,直接注释掉。







先引入头文件
- #include"SelectView.h"
- #include "DispalyView.h"
重写拆分事件
- //拆成一行俩列
- m_spliter.CreateStatic(this, 1, 2);
-
- //左侧右侧具体显示的信息
- m_spliter.CreateView(0,0,RUNTIME_CLASS(CSelectView),CSize(200,500),pContext);
- m_spliter.CreateView(0,1, RUNTIME_CLASS(CDispalyView), CSize(200, 500), pContext);
-
- return TRUE;//代表用户自己拆分


- //初始化树视图
- //获取树控件
- m_treeCtrl = &GetTreeCtrl();
-
- //1、准备图片集合
- HICON icon = AfxGetApp()->LoadIconW(IDI_ICON_RE);
- m_imageList.Create(30, 30, ILC_COLOR32, 1, 1);
- m_imageList.Add(icon);
-
- m_treeCtrl->SetImageList(&m_imageList, TVSIL_NORMAL);
- //2、添加节点
- 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);
InsertItem函数原型:
HTREEITEM InsertItem
(
LPCTSTR lpszItem, //显示的文本
int nImage, //节点的图像索引
int nSelectedImage, //节点被选中时图像的索引
HTREEITEM hParent //指定该节点作为哪个节点的子节点
//NULL代表是根节点,root代表父节点,parent代表子节点
);
create()函数原型:



- //获取当前的选中项
- HTREEITEM item = m_treeCtrl->GetSelectedItem();
-
- //获取选中项里面的内容
- CString name = m_treeCtrl->GetItemText(item);
- MessageBox(name);










从CSelectView.cpp中发送信息



1)、引入要挂载界面的头文件
#include "UserDlg.h"
2)、代码部分
- CCreateContext Context;
- if (wParam == NM_A)
- {
- //MessageBox(L"个人信息界面挂载");
- //挂在界面
- 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);
-
- }




- void CUserDlg::OnInitialUpdate()
- {
- CFormView::OnInitialUpdate();
-
- //初始化
- m_user = TEXT("销售员");
-
- CInfoFile file;
- CString name, pwd;
- file.ReadLogin(name, pwd);
- m_name = name;//获取名称
-
- UpdateData(FALSE);//变量同步到控件上
-
- // TODO: 在此添加专用代码和/或调用基类
- }


- 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;
- CString name, pwd;
- file.ReadLogin(name, pwd);
-
- if (m_newPwd == pwd)
- {
- MessageBox(TEXT("新密码和旧密码不能一致!"));
- return;
- }
- //WritePwd写要求的char *类型
- CStringA tmp;
- tmp = name;
-
- CStringA tmp1;
- tmp1 = m_newPwd;//现在放进去的应该是新的密码,不是旧的密码
- file.WritePwd(tmp.GetBuffer(), tmp1.GetBuffer());
- MessageBox(L"修改成功!");
-
- //情况内容
- m_newPwd.Empty();
- m_surePwd.Empty();
- UpdateData(FALSE);
- }






修改成功。
直接清空密码
- void CUserDlg::OnBnClickedButton2()
- {
- // TODO: 在此添加控件通知处理程序代码
- //清空内容
- m_newPwd.Empty();
- m_surePwd.Empty();
- UpdateData(FALSE);
- }













在入口函数初始化下拉列表
- void CSellDlg1::OnInitialUpdate()
- {
- CFormView::OnInitialUpdate();
-
- // TODO: 在此添加专用代码和/或调用基类
- //初始化销售订单窗口
- //初始化下拉框
- CInfoFile file;
- //把商品读到对象中
- file.ReadDocline();
- list
::iterator it = file.ls.begin(); - for (;it != file.ls.end();it++)
- {
- //遍历商品容器,把容器放到下拉框中
- //string->CString
- m_combo.AddString(CString(it->name.c_str()));
- }
-
- //默认选中第一个
- m_combo.SetCurSel(0);
-
- }

可以使用getline函数获取文件文本中的内容,文件是以ANSI编码保存的则不会出现问题,如果采用其他编码格式(UTF-8,UTF-16会出现乱码),一般存放在string类型的对象中,如果要处理更加复杂的多字节字符集(UTF-8,UTF-16)可以使用wstring来处理。
重写改变事件的目睹为了在切换下拉框的时候跟新其他的信息。

- void CSellDlg1::OnCbnSelchangeCombo1()
- {
- // TODO: 在此添加控件通知处理程序代码
-
- //先获取商品的名称
-
- int index = m_combo.GetCurSel();
- CString name;
- m_combo.GetLBText(index,name);
-
- CInfoFile file;
- //根据商品名称获取到商品的价格和库存,并且显示到控件中
- //把商品读到对象中
- file.ReadDocline();
- list
::iterator it = file.ls.begin(); - for (; it != file.ls.end(); it++)
- {
- if ((CString)it->name.c_str() == name)
- {
- m_price = it->price;
- m_left = it->num;
- //同步到控件上
- UpdateData(FALSE);
- }
-
- }

由于第一个商品的单价库存没有同步,我们可以手动调用一次这个改变事件


实现购买功能
- void CSellDlg1::OnBnClickedButton2()
-
- {
- //UpdateData(TRUE);//没有获取最新数据
- // TODO: 在此添加控件通知处理程序代码
- //购买功能实现
- if (m_num <= 0)
- {
- MessageBox(L"购买数量要大于0");
- return;
- }
- //购买的数量不能大于库存
- if (m_num > m_left)
- {
- MessageBox(L"购买数量不能大于库存");
- return;
- }
- //购买
- //获取到具体要买的商品名称
- int indx = m_combo.GetCurSel();
- CString name;
- m_combo.GetLBText(indx, name);
-
- CInfoFile file;
-
- file.ReadDocline();
- list
::iterator it = file.ls.begin(); - for (; it != file.ls.end(); it++)
- {
- //遍历的商品和这个商品一致减少库存
- if ((CString)it->name.c_str() == name)
- {
- //同步库存量
- it->num -= m_num;
- m_left = it->num;//控件上的库存量
- //告诉用户具体的购买信息
-
- CString str;
- str.Format(_T("商品: %s \r\n单价: %d \r\n个数: %d \r\n总价: %d"), name, m_price, m_num, m_price*m_num);
- m_selfInfo = str;
- UpdateData(FALSE);
- MessageBox(L"购买成功");
-
-
- }






我们购买之后库存并没有减少,所以我们要把数据写到文件中去



- void CSellDlg1::OnBnClickedButton3()
- {
- // TODO: 在此添加控件通知处理程序代码
- //取消按钮
- m_num = 0;
- UpdateData(FALSE);
- //默认选中第一个
- m_combo.SetCurSel(0);
- OnCbnSelchangeCombo1();//更新第一个商品里面的数据
- }


商品添加变量

单价添加变量





头文件引入
#include "ADddDlg.h"
实现挂载
- else if (wParam == NM_D)
- {
- //MessageBox(L"库存添加界面挂载");
- Context.m_pNewViewClass = RUNTIME_CLASS(ADddDlg);
- 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(ADddDlg), CSize(600, 500), &Context);
- ADddDlg *pNewView = (ADddDlg *)m_spliter.GetPane(0, 1);
- m_spliter.RecalcLayout();
- pNewView->OnInitialUpdate();
- m_spliter.SetActivePane(0, 1);
- }



- void ADddDlg::OnInitialUpdate()
- {
- CFormView::OnInitialUpdate();
-
- // TODO: 在此添加专用代码和/或调用基类
-
- //初始化下拉框
- CInfoFile file;
- //把商品读到对象中
- file.ReadDocline();
- list
::iterator it = file.ls.begin(); - for (; it != file.ls.end(); it++)
- {
- //遍历商品容器,把容器放到下拉框中
- //string->CString
- m_combo.AddString(CString(it->name.c_str()));
- }
-
- //默认选中第一个商品
- m_combo.SetCurSel(0);
- OnCbnSelchangeCombo1();//手动调用更新第一个商品数据
- }
-
-
- void ADddDlg::OnCbnSelchangeCombo1()
- {
- // TODO: 在此添加控件通知处理程序代码
- //先获取商品的名称
-
- int index = m_combo.GetCurSel();
- CString name;
- m_combo.GetLBText(index, name);
-
- CInfoFile file;
- //根据商品名称获取到商品的价格和库存,并且显示到控件中
- //把商品读到对象中
- file.ReadDocline();
- list
::iterator it = file.ls.begin(); - for (; it != file.ls.end(); it++)
- {
- if ((CString)it->name.c_str() == name)
- {
- m_price1 = it->price;
-
- //同步到控件上
- UpdateData(FALSE);
- }
-
- }
添加事件代码
- void ADddDlg::OnBnClickedButton3()
- {
- // TODO: 在此添加控件通知处理程序代码
-
- //添加商品按钮功能实现
- //拿到最新的数据
- UpdateData(TRUE);
-
- if (m_num1 <= 0)
- {
- MessageBox(L"添加的数量必须大于0!");
- return;
- }
- //先获取你要添加的商品名称
- int indx = m_combo.GetCurSel();
- CString name;
- m_combo.GetLBText(indx, name);
- CInfoFile file;
- file.ReadDocline();
- list
::iterator it = file.ls.begin(); - for (; it != file.ls.end(); it++)
- {
- if ((CString)it->name.c_str() == name)
- {
- //添加库存
- it->num += m_num1;
- m_num1 = 0;
- UpdateData(FALSE);
- MessageBox(L"添加成功!");
- }
- //把商品同步到文件中
- file.WriteDocline();
-
- }
运行效果



- void ADddDlg::OnBnClickedButton4()
- {
- // TODO: 在此添加控件通知处理程序代码
- m_num1 = 0;
- UpdateData(FALSE);
- m_combo.SetCurSel(0);
- OnCbnSelchangeCombo1();
-
- }


- void ADddDlg::OnBnClickedButton5()
- {
- // TODO: 在此添加控件通知处理程序代码
- //拿到最新的数据
- UpdateData(TRUE);
- //验证添加新商品
- //验证数据的有效性
- if (m_name2.IsEmpty() || m_num2 <= 0 || m_price2 <= 0)
- {
- MessageBox(L"你输入的信息有误!");
- return;
- }
-
- CInfoFile file;
- file.ReadDocline();
-
- file.Addline(m_name2, m_num2, m_price2);
- file.WriteDocline();
- MessageBox(L"商品添加成功!");
-
- //同步到左侧下拉框中
- m_combo.InsertString(0, m_name2);
- m_combo.SetCurSel(0);
- OnCbnSelchangeCombo1();
-
- //清空添加的新数据
- m_name2.Empty();
- m_num2 = 0;
- m_price2 = 0;
- UpdateData(FALSE);
- }



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

