您的位置:首页 > 健康 > 养生 > 系统优化升级95%后不动了_重庆seo怎么样_seo搜索引擎优化策略_上海seo网站推广

系统优化升级95%后不动了_重庆seo怎么样_seo搜索引擎优化策略_上海seo网站推广

2025/3/11 7:35:47 来源:https://blog.csdn.net/qq_36349997/article/details/146166854  浏览:    关键词:系统优化升级95%后不动了_重庆seo怎么样_seo搜索引擎优化策略_上海seo网站推广
系统优化升级95%后不动了_重庆seo怎么样_seo搜索引擎优化策略_上海seo网站推广

预览

源链接:https://blog.iyatt.com/?p=19158

file
file
file
file
file
file
file

测试环境

  • https://blog.iyatt.com/?p=18843#%E7%8E%AF%E5%A2%83

项目

参考黑马程序员的案例教程进行实践的记录,部分内容自行修改过,比如原案例直接读写文件保存账号、密码、数据,这里改为使用 SQLite3 数据库。
注意 VS 默认头文件扩展名用的 .h,我是喜欢在 C++ 中使用扩展名 .hpp,只要不是模板创建的代码部分,是我自己添加的都使用 .hpp 扩展名。
源码:下载地址见文首源链接

新建项目

新建一个 MFC 应用,项目名 saleSystem应用程序类型单个文档项目样式MFC standard
file

用户界面功能经典菜单选项,再点完成进行创建
file

不使用安全函数

在项目名称上右键属性
file

展开配置属性->C/C++->代码生成,在安全检查中禁用安全检查
file

添加窗口图标

user.ico 放到项目目录下的res目录里
file

切换到资源视图选项卡,展开上面的资源分支,在 Icon 上右键添加资源
file

导入
file

选择图标文件
file

ID改为IDI_ICON_WIN
file

类视图下,CMainFrame类中的OnCreate方法里添加代码
file

	// 加载图标HICON winIcon = AfxGetApp()->LoadIconW(IDI_ICON_WIN);// 设置小图标SetIcon(winIcon, FALSE);

{F5}调试运行,点加载图标文件
file

运行效果
file

设置窗口大小和居中显示

类视图下,CMainFrame类中的OnCreate方法里添加代码

	// 设置位置(0,0)和窗口大小(800×600)MoveWindow(0, 0, 800, 600);// 居中显示CenterWindow();

file

设置窗口标题

资源视图下,展开资源树,双击打开 String Table,在底部添加一个 ID 为ID_STRING_PROJECTNAME,值为销售系统
file

类视图CsaleSystemDoc类中OnNewDocument方法下添加代码

	CString projectName;projectName.LoadStringW(ID_STRING_PROJECTNAME); // 导入字符串资源SetTitle(projectName); // 设置窗口标题

file

运行效果
file

设计 SQLite3 数据库读写实现

这里实现账号、密码、商品信息的读写,数据库采用 SQLite3,配置 SQLite3 环境参考:https://blog.iyatt.com/?p=19187

手动创建一个数据库文件

在项目目录下打开终端,执行命令打开数据库文件 saleSystem.sb(不存在会自动创建),打开后会处于命令交互模式

sqlite3 saleSystem.sqlite3

file

新建一张表用于存储账号、密码,并写入初始账号、密码(账号:admin,密码:123456)

create table users
(id integer primary key autoincrement ,username text not null unique ,password text not null
);insert into users (username, password) values ('admin', '123456');

file

在创建一张表用于存储商品数据,并插入几条商品数据

create table products (id integer primary key autoincrement ,name text not null unique ,price real not null ,stock integer not null
);insert into products (name, price, stock) values('桌子', 199.9, 5),('椅子', 49.8, 10);

file

退出交互模式

.exit

file

读写实现

类视图下,项目上右键添加->
file

创建一个类,类名StoreManager
file

StoreManager.hpp

#pragma once
extern "C"
{#include "sqlite3.h"
}#include <vector>typedef struct
{int id;CString name;double price;int stock;
}productStruct;typedef struct
{CString username;CString password;
}loginInfoStruct;typedef std::vector<productStruct> productsVector;class StoreManager
{
private:static sqlite3* db;static productStruct product;static loginInfoStruct loginInfo;private:static int readLoginInfoCallback(void* data, int argc, char** argv, char** colName);/*** @brief UTF-8 编码窄字符串转 GBK 编码 CString* @param utf8Str * @return */static CString utf8ToGbk(const char* utf8Str);/*** @brief GBK 编码 CString 转 UTF-8 窄字符串* @param gbkStr * @return */static char* gbkToUtf8(const CString& gbkStr);public:/*** @brief 连接数据库* @param databasePath 数据库文件路径*/static void connect(CString& databasePath);/*** @brief 读取登录信息* @param username 用户名* @param password 密码*/static void readLogin(CString& username, CString& password);/*** @brief 修改密码* @param username 要修改密码的用户 * @param password 新密码*/static bool writePassword(CString& username, CString& password);/*** @brief 关闭数据库*/static void close();/*** @brief 读取商品信息* @param products 商品信息数组*/static void readProducts(productsVector& products);/*** @brief 写入商品信息* @param products 商品信息数据*/static void writeProducts(productsVector& products);/*** @brief 修改商品信息* @param products */static void modifyProducts(productsVector& products);
};

StoreManager.cpp

#include "pch.h"
#include "StoreManager.hpp"#include <string>
#include <stdexcept>sqlite3* StoreManager::db = nullptr;
loginInfoStruct StoreManager::loginInfo;
productStruct StoreManager::product;void StoreManager::connect(CString& databasePath)
{if (StoreManager::db != nullptr){return;}CW2A databasePathA(databasePath.GetString()); // 宽字符串转普通字符串if (sqlite3_open(databasePathA, &StoreManager::db) != SQLITE_OK){std::string error = "打开数据库失败:" + std::string(sqlite3_errmsg(StoreManager::db));throw std::runtime_error(error);}
}void StoreManager::close()
{if (StoreManager::db != nullptr){sqlite3_free(StoreManager::db);StoreManager::db = nullptr;}
}int StoreManager::readLoginInfoCallback(void* data, int argc, char** argv, char** colName)
{(void)data;(void)argc;(void)colName;StoreManager::loginInfo.username = argv[1];StoreManager::loginInfo.password = argv[2];return 0;
}void StoreManager::readLogin(CString& username, CString& password)
{if (StoreManager::db == nullptr){std::string error = "请连接数据库后再读取登录信息";throw std::runtime_error(error);}const char* sqlA = "select * from users";char* errorA = nullptr;if (sqlite3_exec(StoreManager::db, sqlA, StoreManager::readLoginInfoCallback, nullptr, &errorA) != SQLITE_OK){std::string error = "读取登录信息失败:" + std::string(errorA);sqlite3_free(errorA);throw std::runtime_error(error);}username = StoreManager::loginInfo.username;password = StoreManager::loginInfo.password;
}bool StoreManager::writePassword(CString& username, CString& password)
{if (StoreManager::db == nullptr){std::string error = "请连接数据库后再读取登录信息";throw std::runtime_error(error);}CString sql;sql.Format(L"update users set password = '%s' where username = '%s'", password.GetString(), username.GetString());CW2A sqlA(sql);char* errorA = nullptr;if (sqlite3_exec(StoreManager::db, sqlA, nullptr, nullptr, &errorA) != SQLITE_OK){CA2W errorW(errorA);AfxMessageBox(errorW);sqlite3_free(errorA);return false;}return true;
}CString StoreManager::utf8ToGbk(const char* utf8Str)
{int wideCharLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str, -1, nullptr, 0);if (wideCharLen <= 0){return CString();}wchar_t* wideCharStr = new wchar_t[wideCharLen];MultiByteToWideChar(CP_UTF8, 0, utf8Str, -1, wideCharStr, wideCharLen);int gbkLen = WideCharToMultiByte(CP_ACP, 0, wideCharStr, -1, nullptr, 0, nullptr, nullptr);if (gbkLen <= 0){delete[] wideCharStr;return CString();}char* gbkStr = new char[gbkLen];WideCharToMultiByte(CP_ACP, 0, wideCharStr, -1, gbkStr, gbkLen, nullptr, nullptr);CString result(gbkStr);delete[] wideCharStr;delete[] gbkStr;return result;
}char* StoreManager::gbkToUtf8(const CString& gbkStr)
{// 获取宽字符字符串的长度int wideCharLen = gbkStr.GetLength();if (wideCharLen <= 0){return nullptr; // 如果字符串为空,直接返回 nullptr}// 将 CString 转换为宽字符数组const WCHAR* gbkW = gbkStr.GetString();// 获取需要的 UTF-8 编码字符串的长度(包括结尾的 '\0')int utf8Len = WideCharToMultiByte(CP_UTF8, 0, gbkW, -1, nullptr, 0, nullptr, nullptr);if (utf8Len <= 0){return nullptr; // 如果转换失败,返回 nullptr}// 分配内存用于存储 UTF-8 编码的字符串char* utf8Str = new char[utf8Len];// 执行转换if (WideCharToMultiByte(CP_UTF8, 0, gbkW, -1, utf8Str, utf8Len, nullptr, nullptr) == 0){delete[] utf8Str; // 如果转换失败,释放已分配的内存return nullptr;}return utf8Str; // 返回转换后的 UTF-8 字符串
}void StoreManager::readProducts(productsVector& products)
{if (StoreManager::db == nullptr){std::string error = "请连接数据库后再读取商品信息";throw std::runtime_error(error);}products.clear();const char* sqlA = "select * from products";char** result = nullptr;char* errorA = nullptr;int rows, cols;if (sqlite3_get_table(StoreManager::db, sqlA, &result, &rows, &cols, &errorA) != SQLITE_OK){CA2W errorW(errorA);AfxMessageBox(errorW);sqlite3_free(errorA);return;}productStruct product;for (int row = 1; row <= rows; ++row){product.id = std::stoi(result[row * cols + 0]);product.name = StoreManager::utf8ToGbk(result[row * cols + 1]);product.price = std::stod(result[row * cols + 2]);product.stock = std::stoi(result[row * cols + 3]);products.push_back(product);}
}void StoreManager::writeProducts(productsVector& products)
{if (StoreManager::db == nullptr){std::string error = "请连接数据库后再写入商品信息";throw std::runtime_error(error);}CString sql;char* errorA = nullptr;for (productStruct product : products){sql.Format(L"insert into products (name, price, stock) values ('%s', %f, %d)", product.name.GetString(), product.price, product.stock);char* sqlA = StoreManager::gbkToUtf8(sql);if (sqlite3_exec(StoreManager::db, sqlA, nullptr, nullptr, &errorA) != SQLITE_OK){CA2W errorW(errorA);AfxMessageBox(errorW);sqlite3_free(errorA);delete[] sqlA;break;}else{delete[] sqlA;}}
}void StoreManager::modifyProducts(productsVector& products)
{if (StoreManager::db == nullptr){std::string error = "请连接数据库后再修改商品信息";throw std::runtime_error(error);}CString sql;char* errorA = nullptr;for (productStruct product : products){sql.Format(L"update products set price = %f, stock = %d where name = '%s'", product.price, product.stock, product.name.GetString());char* sqlA = StoreManager::gbkToUtf8(sql);if (sqlite3_exec(StoreManager::db, sqlA, nullptr, nullptr, &errorA) != SQLITE_OK){CA2W errorW(errorA);AfxMessageBox(errorW);sqlite3_free(errorA);delete[] sqlA;break;}else{delete[] sqlA;}}
}

保证程序退出时关闭数据库

类视图下,CsaleSystemApp类中,找一个位置写入。注意要引用 StoreManager.hpp 头文件

struct Release
{~Release(){StoreManager::close();}
} release;

file

可以把 C++ 中的 struct 看作是默认 public 的 class,这里析构函数需要 public,使用 struct 就不需要额外写一个public:,然后实例化一个对象,这样程序结束的时候就会自动调用这个析构函数,完成资源的释放。

登录对话框

界面设计

资源视图下,Dialog上右键插入
file

将对话框 ID 改为 DIALOG_LOGIN
file

添加控件,并设置好描述文字,设置窗口标题
(使用 Static Text、Edit Control 和 Button)
file

在对话框空白处右键添加类
file

创建一个类 LoginDialog
file

为用户名编辑框创建变量usernameEditControl,访问选private
file

file

同样为密码编辑框创建变量passwordEditControl
file

功能实现

让登录对话框在文档之前创建

类视图下,CsaleSystemApp 类中的 InitInstance 方法中
file

找到**CWinApp::InitInstance();**的位置,在它之前以模态的方式运行登录对话框。注意要引用对话框的头文件 LoginDialog.hpp
然后判断返回值,后续实现中如果登录成功才会调用 OnOK,这边得到的返回值就是 IDOK,如果不是那就说明点击了取消登录或右上角的关闭按钮,以及其它操作,这时候就要直接返回,就不会创建后续文档页面。

	LoginDialog loginDialog;if (loginDialog.DoModal() != IDOK){return TRUE;}

file

这时候调试运行就会先显示登录对话框,但是关闭登录对话框后会显示文档页面,后续还要处理这个逻辑,只有登录验证才应该显示后续的文档。
file

数据库连接

资源视图下,StringTable 添加一个字段 DATABASE_PATH,设置 SQLite3 数据库文件的路径,这里就在项目目录下,使用相对路径
file

类视图下,在登录对话框类LoginDialog上右键属性
file

上面点击图标切换到重写页面,添加(重写) OnInitDialog
file

然后回到 OnInitDialog 函数中,添加连接数据库的代码。注意前面要引用数据库读写实现的头文件 StoreManager.hpp

	CString databasePath;databasePath.LoadStringW(DATABASE_PATH);StoreManager::connect(databasePath);

file

登录按钮回调实现

双击登录按钮会直接创建点击事件的回调
file

写入代码

	// 读取用户输入的用户名和密码CString inputUsername, inputPassword;this->usernameEditControl.GetWindowTextW(inputUsername);this->passwordEditControl.GetWindowTextW(inputPassword);// 读取数据库中的用户名和密码CString username, password;StoreManager::readLogin(username, password);// 判断用户名和密码if (inputUsername == username){if (inputPassword != password){MessageBox(L"密码错误");this->usernameEditControl.SetWindowTextW(L"");this->passwordEditControl.SetWindowTextW(L"");}else{MessageBox(L"登录成功");CDialogEx::OnOK();}}else{MessageBox(L"用户名不存在");this->usernameEditControl.SetWindowTextW(L"");this->passwordEditControl.SetWindowTextW(L"");}

file

调试运行
file

file

取消按钮回调实现

双击取消按钮,创建点击事件回调
file

点击取消调用取消方法

	CDialogEx::OnCancel();

file

修改回车键为登录

对话框默认状态下按回车会调用 CDialogEx::OnOK(),这就会让登录验证成为摆设,相当于点击了登录对话框的 OK,那么接下来就会直接进入文档页面。
另外按照一般使用习惯回车键就是确认输入,这里也就是确认登录。
类视图下,LoginDialog类上右键属性,重写对话框的 OnOK
file

注释掉CDialogEx::OnOK();,然后调用登录按钮点击事件的回调方法,这就按回车就等于是点击登录按钮。

	this->OnBnClickedButton1();

file

静态拆分窗口

自定义视图类

类视图中项目名上右键类向导
file

下拉MFC 类
file

类名 SelectView,基类CTreeView
file

同样再添加一个类DisplayView,基类CFormView
file

创建完上面两个类,在类向导页面点确定,编译在下面可能看到一堆 SelectView 头文件和源文件的报错
file

在头文件增加引用 #include “afxcview.h”
file

再编译就好了
file

拆分窗口

类视图中,点开 CMainFrame 类,声明一个对象

private:CSplitterWnd splitter;

file

CMainFrame上右键属性
file

重写 OnCreateClient
file

把原来的返回注释了,重新写
注意需要引用 SelectView.hppDisplayView.hpp 头文件

	// 拆分为 1 行 2 列this->splitter.CreateStatic(this, 1, 2);// 创建左侧视图this->splitter.CreateView(0, 0, RUNTIME_CLASS(SelectView), CSize(200, 500), pContext);// 创建右侧视图this->splitter.CreateView(0, 1, RUNTIME_CLASS(DisplayView), CSize(600, 500), pContext);return TRUE;

file

调试运行,登录后可以看到下图的布局
file

左侧树视图

添加功能节点

资源视图下,Icon右键添加资源
file

导入
file

选择 re.ico 文件
file

ID 重设为 IDI_ICON_RE
file

类视图下双击SelectView类,在类头文件中增加

private:CTreeCtrl* treeCtrl;CImageList imageList;

file

SelectView 类上右键属性
file

重写 OnInitialUpdate
file

写入

	// 加载图标HICON icon = AfxGetApp()->LoadIconW(IDI_ICON_RE);// 创建图片列表this->imageList.Create(30, 30, ILC_COLOR32, 1, 1);// 添加图标this->imageList.Add(icon);// 获取树控件this->treeCtrl = &GetTreeCtrl();// 树控件设置图片列表this->treeCtrl->SetImageList(&this->imageList, TVSIL_NORMAL);// 树控件设置节点this->treeCtrl->InsertItem(L"个人信息", 0, 0, TVI_ROOT, TVI_LAST);this->treeCtrl->InsertItem(L"销售管理", 0, 0, TVI_ROOT, TVI_LAST);this->treeCtrl->InsertItem(L"库存信息", 0, 0, TVI_ROOT, TVI_LAST);this->treeCtrl->InsertItem(L"库存添加", 0, 0, TVI_ROOT, TVI_LAST);this->treeCtrl->InsertItem(L"库存删除", 0, 0, TVI_ROOT, TVI_LAST);

file

运行登陆后
file

功能节点消息处理

查看 SelectView 类属性,添加消息TVN_SELCHANGED 的回调
file

写入

	// 获取选中的项目HTREEITEM item = this->treeCtrl->GetSelectedItem();// 获取选中项文本内容CString selectedText = this->treeCtrl->GetItemText(item);if (selectedText == L"个人信息"){}else if (selectedText == L"销售管理"){}else if (selectedText == L"库存信息"){}else if (selectedText == L"库存添加"){}else if (selectedText == L"库存删除"){}

file

个人信息页面

界面设计

资源视图下,Dialog上右键插入
file

ID改为DIALOG_USER边框改为None样式改为Child
file

file

绘制页面,原来的确定和取消按钮保留
(Group Box、Static Text、Edit Control)
file

在对话框空白处右键添加类
file

类名 UserDialog,基类CFormView
file

下面分别为 4 个编辑框创建变量
身份
file

变量名positionEditControl
file

用户名编辑框变量usernameEditControl
file

新密码编辑框变量newPasswordEditControl
file

确定密码编辑框变量confirmPasswordEditControl
file

功能实现

初始化界面

类视图UserDialog 类上右键属性
file

重写OnInitialUpdate
file

	this->positionEditControl.SetWindowTextW(L"销售员");

file

确定修改密码

双击确定按钮,编辑确定按钮的单机事件回调,注意要引用 StoreManager.hpp 头文件

if (this->usernameEditControl.GetWindowTextLengthW() == 0){MessageBox(L"输入用户名不能为空");return;}if (this->newPasswordEditControl.GetWindowTextLengthW() == 0 || this->confirmPasswordEditControl.GetWindowTextLengthW() == 0){MessageBox(L"输入密码不能为空");return;}CString newPassword, confirmPassword;this->newPasswordEditControl.GetWindowTextW(newPassword);this->confirmPasswordEditControl.GetWindowTextW(confirmPassword);if (newPassword != confirmPassword){MessageBox(L"输入密码和确定密码不同");return;}CString oldPassword, username, inputUsername;StoreManager::readLogin(username, oldPassword);this->usernameEditControl.GetWindowTextW(inputUsername);if (inputUsername != username){MessageBox(L"用户名错误");return;}if (newPassword == oldPassword){MessageBox(L"新密码和原密码相同");return;}if (StoreManager::writePassword(inputUsername, newPassword)){MessageBox(L"修改密码成功");}else{MessageBox(L"修改密码失败");}

file

取消修改密码

双击取消按钮

	this->usernameEditControl.SetWindowTextW(L"");this->newPasswordEditControl.SetWindowTextW(L"");this->confirmPasswordEditControl.SetWindowTextW(L"");

file

界面挂载

自定义消息发送

类视图中双击CMainFrame类进行编辑,写入自定义消息

constexpr UINT NM_USER = WM_USER + 100;
constexpr UINT NM_SELL = WM_USER + 101;
constexpr UINT NM_INFO = WM_USER + 102;
constexpr UINT NM_ADD = WM_USER + 103;
constexpr UINT NM_DEL = WM_USER + 104;

file

添加自定义消息处理函数,头文件中添加声明

protected:afx_msg LRESULT onMyChange(WPARAM wParam, LPARAM lParam);

file

源文件中添加定义

afx_msg LRESULT CMainFrame::onMyChange(WPARAM wParam, LPARAM lParam)
{}

file

然后看到 BEGIN_MESSAGE_MAP,在它和 END_MESSAGE_MAP() 之间添加代码

	// 响应自定义消息ON_MESSAGE(NM_USER, onMyChange)ON_MESSAGE(NM_SELL, onMyChange)ON_MESSAGE(NM_INFO, onMyChange)ON_MESSAGE(NM_ADD, onMyChange)ON_MESSAGE(NM_DEL, onMyChange)

file

编辑 SelectView 类中的 OnTvnSelchanged 方法,注意需要引用 MainFrm.h 头文件

	if (selectedText == L"个人信息"){// 将消息放入消息队列::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), // 框架窗口对象指针NM_USER, // 发送自定义消息NM_USER, // 消息的附加参数0 // 消息的附加参数,这里不使用);}else if (selectedText == L"销售管理"){::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_SELL, NM_SELL, 0);}else if (selectedText == L"库存信息"){::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_INFO, NM_INFO, 0);}else if (selectedText == L"库存添加"){::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_ADD, NM_ADD, 0);}else if (selectedText == L"库存删除"){::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_DEL, NM_DEL, 0);}

file

自定义消息处理

编辑 CMainFrame 类中的 OnMyChange 方法,注意引用 UserDialog.hpp 头文件

	CCreateContext context;this->splitter.DeleteView(0, 1);switch (wParam){case NM_USER:{context.m_pNewViewClass = RUNTIME_CLASS(UserDialog);this->splitter.CreateView(0, 1, RUNTIME_CLASS(UserDialog), CSize(600, 500), &context);((UserDialog*)this->splitter.GetPane(0, 1))->OnInitialUpdate();break;}case NM_SELL:{break;}case NM_INFO:{break;}case NM_ADD:{break;}case NM_DEL:{break;}}this->splitter.RecalcLayout();this->splitter.SetActivePane(0, 1);context.m_pLastView = (CFormView*)this->splitter.GetPane(0, 1);context.m_pCurrentFrame = this;return 0;

file

调试运行效果
file
file
file
file
file
file

销售管理页面

界面设计

资源视图下插入新的对话框
file

ID改为DIALOG_SELL边框改为None样式改为Child
file

绘制界面,不删除原先的确定和取消按钮,确定的描述文字改成购买,商品名那里的 Combo Box 属性里的类型改为下拉列表,订单信息那里的大编辑框属性里多行垂直滚动依次设置为True,数量编辑框属性里的数字改为True
(Group Box、Static Text、Edit Control、Combo Box)
file

在对话框空白处右键添加类
file

类名为SellDialog,基类为CFormView
file

为商品名组合框创建变量productNameComboBoxControl
file
file

为单价编辑框创建变量priceEditValue,注意类别选值,变量类型填 double
file

为数量编辑框创建变量numEditValue,类别选值,变量类型填 int
file

为订单信息编辑框创建变量sellEditControl
file

界面挂载

编辑CMainFrame类中的OnMyChange方法,在 case NM_SELL 下写。注意引用 SellDialog.hpp 头文件

			context.m_pNewViewClass = RUNTIME_CLASS(SellDialog);this->splitter.CreateView(0, 1, RUNTIME_CLASS(SellDialog), CSize(600, 500), &context);((SellDialog*)this->splitter.GetPane(0, 1))->OnInitialUpdate();

file

调试运行
file

功能实现

初始化界面

CellDialog类上右键属性,重写OnInitialUpdate方法
file

这里从数据库读取商品数据,把商品名设置给组合框,注意引用 StoreManager.hpp 头文件

	productsVector products;StoreManager::readProducts(products);for (productStruct product : products){this->productNameComboBoxControl.AddString(product.name);}this->productNameComboBoxControl.SetCurSel(0);

file

调试运行
file

组合框切换刷新信息

在商品名组合框上右键属性
file

创建 CBN_SELCHANGE 事件的回调方法
file

写入

	// 获取当前选中项的索引int curIdx = this->productNameComboBoxControl.GetCurSel();// 获取当前选中项的文本CString curText;this->productNameComboBoxControl.GetLBText(curIdx, curText);productsVector products;StoreManager::readProducts(products);for (productStruct product : products){if (curText == product.name){this->priceEditValue = product.price;this->numEditValue = 0;UpdateData(FALSE);break;}}

file

另外在前面重写的 OnInitialUpdate 方法末尾调用一下,实现初始化

	this->OnCbnSelchangeCombo1();

file

调试运行
file
file

购买实现

双击购买按钮,创建点击事件回调,写入

	if (this->numEditValue == 0){MessageBox(L"购买数量不能为 0");return;}int curIdx = this->productNameComboBoxControl.GetCurSel();CString curText;this->productNameComboBoxControl.GetLBText(curIdx, curText);productsVector products;StoreManager::readProducts(products);for (productsVector::iterator product = products.begin(); product != products.end(); ++product){if (curText == product->name){if (this->numEditValue > product->stock){CString msg;msg.Format(L"购买数量超出库存,当前库存数量:%d,请减小购买数量后再试", product->stock);MessageBox(msg.GetString());return;}product->stock = product->stock - this->numEditValue;productsVector modifyProduct = { *product };StoreManager::modifyProducts(modifyProduct);CString sellMsg;sellMsg.Format(L"商品:%s\r\n单价:%f\r\n数量:%d\r\n总价:%f\r\n剩余库存:%d", product->name.GetString(), product->price, this->numEditValue, product->price * this->numEditValue, product->stock);this->sellEditControl.SetWindowTextW(sellMsg.GetString());break;}}

file

调试运行效果
file
file
file
file

取消

双击取消按钮,创建事件回调

	this->sellEditControl.SetWindowTextW(L"");this->numEditValue = 0;UpdateData(FALSE);

file

库存信息页面

界面设计

添加一个对话框
file

属性里,ID 设置为DIALOG_INFO,边框选None,样式选Child
file
file

绘制界面,删除确定和取消按钮,List Control 的视图改为Report
(Static Text、List Control)
file

对话框空白处右键添加类
file

类名InfoDialog,基类CFormView
file

在列表控件上右键添加变量infoListControl
file

界面挂载

编辑CMainFrame类中的onMyChange方法,在case NM_INFO下写入,注意引用头文件 InfoDialog.hpp

			context.m_pNewViewClass = RUNTIME_CLASS(InfoDialog);this->splitter.CreateView(0, 1, RUNTIME_CLASS(InfoDialog), CSize(600, 500), &context);((InfoDialog*)this->splitter.GetPane(0, 1))->OnInitialUpdate();

file

调试运行
file

功能实现

InfoDialog 类上右键 属性
file

重写 OnInitialUpdate 方法
file

注意引用 StoreManager.hpp 头文件

	// 显示表头this->infoListControl.SetExtendedStyle(this->infoListControl.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);CString field[] = { L"商品ID", L"商品名称", L"商品价格", L"库存数量" };for (int i = 0; i < sizeof(field) / sizeof(field[0]); ++i){this->infoListControl.InsertColumn(i, field[i], LVCFMT_CENTER, 90);}// 读取商品信息productsVector products;StoreManager::readProducts(products);// 显示数据int idx = 0;CString tmpStr;for (productsVector::iterator product = products.begin(); product != products.end(); ++product){tmpStr.Format(L"%d", product->id);this->infoListControl.InsertItem(idx, tmpStr);this->infoListControl.SetItemText(idx, 1, product->name);tmpStr.Format(L"%f", product->price);this->infoListControl.SetItemText(idx, 2, tmpStr);tmpStr.Format(L"%d", product->stock);this->infoListControl.SetItemText(idx, 3, tmpStr);++idx;}

file

调试运行
file

库存添加页面

界面设计

添加一个对话框
file

ID 改为 DIALOG_ADD,边框改为None,样式改为Child
file
file

绘制界面,删除原来的确定和取消按钮,个数编辑框属性的数字设置为True,Combo Box 属性类型选下拉列表,库存单价编辑库属性只读设置为True
(Static Text、Group Box、Edit Control、Button、Combo Box)
file

在对话框空白处右键添加类AddDialog,基类CFormView
file

为组合框和编辑框添加变量
file

库存商品编辑框,变量名stockProductComboBoxControl,访问private
file

库存价格编辑框,变量名stockPriceEditValue,类别,访问private,变量类型double
file

库存个数编辑框,变量名stockNumEditValue,类别,访问private,变量类型int
file

新商品编辑框,变量名newProductEditValue,类别,访问private
file

新商品单价编辑框,变量名newPriceEditValue,类别,访问private,变量类型double
file

新商品库存编辑框,变量名newNumEditValue,类别,访问private,变量类型int
file

界面挂载

编辑 CMainFrame 类中 onMyChange 方法,在 case NM_ADD 中添加,注意引用头文件 AddDialog.hpp

			context.m_pNewViewClass = RUNTIME_CLASS(AddDialog);this->splitter.CreateView(0, 1, RUNTIME_CLASS(AddDialog), CSize(600, 500), &context);((AddDialog*)this->splitter.GetPane(0, 1))->OnInitialUpdate();

file

调试运行
file

功能实现

初始化库存组合框

重写 OnInitialUpdate 方法
file
file

注意引用 StoreManager.hpp 头文件

	productsVector products;StoreManager::readProducts(products);for (productsVector::iterator product = products.begin(); product != products.end(); ++product){this->stockProductComboBoxControl.AddString(product->name);}this->stockProductComboBoxControl.SetCurSel(0);

file

调试运行
file

库存组合框切换事件回调

file
file

	int curIdx = this->stockProductComboBoxControl.GetCurSel();CString curText;this->stockProductComboBoxControl.GetLBText(curIdx, curText);productsVector products;StoreManager::readProducts(products);for (productsVector::iterator product = products.begin(); product != products.end(); ++product){if (curText == product->name){this->stockPriceEditValue = product->price;this->stockNumEditValue = 0;UpdateData(FALSE);break;}}

file

OnInitialUpdate 里调用这个方法,保证初始化的时候正确设置

	this->OnCbnSelchangeCombo2();

file

调试运行
file

添加库存

双击添加库存按钮

	UpdateData(TRUE);if (this->stockNumEditValue <= 0 || this->stockPriceEditValue <= 0){MessageBox(L"数量必须大于 0,或价格不能低于 0");return;}int curIdx = this->stockProductComboBoxControl.GetCurSel();CString curText;this->stockProductComboBoxControl.GetLBText(curIdx, curText);productsVector products;StoreManager::readProducts(products);for (productsVector::iterator product = products.begin(); product != products.end(); ++product){if (curText == product->name){product->stock += this->stockNumEditValue;CString msg;productsVector tmpProduct = { *product };StoreManager::modifyProducts(tmpProduct);msg.Format(L"增加库存:%d,库存总量:%d", this->stockNumEditValue, product->stock);MessageBox(msg.GetString());break;}}this->stockNumEditValue = 0;UpdateData(FALSE);

file

调试运行
file

取消库存设置

双击取消库存设置按钮

	this->stockNumEditValue = 0;UpdateData(FALSE);

file

添加新商品

双击添加新商品按钮

	UpdateData(TRUE);if (this->newNumEditValue <= 0 || this->newPriceEditValue <= 0 || this->newProductEditValue.IsEmpty()){MessageBox(L"输入信息有误");return;}productStruct product;product.name = this->newProductEditValue;product.price = this->newPriceEditValue;product.stock = this->newNumEditValue;productsVector tmpProduct = { product };StoreManager::writeProducts(tmpProduct);this->newProductEditValue.Empty();this->newPriceEditValue = 0;this->newNumEditValue = 0;UpdateData(FALSE);this->OnInitialUpdate();CString msg;msg.Format(L"添加商品:%s,单价:%f,数量:%d", product.name.GetString(), product.price, product.stock);MessageBox(msg.GetString());

file

调试运行
file

取消商品设置

双击取消商品设置按钮

	this->newProductEditValue.Empty();this->newPriceEditValue = 0;this->newNumEditValue = 0;UpdateData(FALSE);

file

库存删除页面

界面设计

添加一个对话款
file

ID 改为DIALOG_DEL,边框改为None,样式改为Child
file

绘制界面,保留确定和取消按钮,Combo Box 类型改为下拉列表,数量编辑框属性数字设置为True,设置单价编辑框只读
(Group Box、Static Text、Combo Box、Edit Control)
file

为对话框添加类DelDialog,基类CFormView
file
file

为组合框和编辑框添加变量
商品名 productComboBoxControl
file
file

单价 priceEditValue
file

数量 numEditValue
file

界面挂载

编辑 CMainFrame 类中 onMyChange 方法,在 case NM_DEL 下写入,注意引用头文件 DelDialog.hpp

			context.m_pNewViewClass = RUNTIME_CLASS(DelDialog);this->splitter.CreateView(0, 1, RUNTIME_CLASS(DelDialog), CSize(600, 500), &context);((DelDialog*)this->splitter.GetPane(0, 1))->OnInitialUpdate();

file

调试运行
file

功能实现

初始化界面

重写 OnInitialUpdate 方法
file
file

注意引用 StoreManager.hpp 头文件

	productsVector products;StoreManager::readProducts(products);for (productsVector::iterator product = products.begin(); product != products.end(); ++product){this->productComboBoxControl.AddString(product->name);}this->productComboBoxControl.SetCurSel(0);

file

调试运行
file

组合框切换

file
file

	int curIdx = this->productComboBoxControl.GetCurSel();CString curText;this->productComboBoxControl.GetLBText(curIdx, curText);productsVector products;StoreManager::readProducts(products);for (productsVector::iterator product = products.begin(); product != products.end(); ++product){if (curText == product->name){this->priceEditValue = product->price;this->numEditValue = 0;UpdateData(FALSE);break;}}

file

	this->OnCbnSelchangeCombo1();

file

调试运行
file

确定按钮

双击确定按钮

	UpdateData(TRUE);if (this->numEditValue <= 0){MessageBox(L"数量必须大于 0");return;}int curIdx = this->productComboBoxControl.GetCurSel();CString curText;this->productComboBoxControl.GetLBText(curIdx, curText);productsVector products;StoreManager::readProducts(products);for (productsVector::iterator product = products.begin(); product != products.end(); ++product){if (curText == product->name){product->stock -= this->numEditValue;productsVector tmpProduct = { *product };StoreManager::modifyProducts(tmpProduct);CString msg;msg.Format(L"删除商品:%s, 单价:%f,数量:%d", product->name.GetString(), product->price, this->numEditValue);MessageBox(msg.GetString());break;}}this->numEditValue = 0;UpdateData(FALSE);

file

调试运行
file

取消按钮

双击取消按钮

	this->numEditValue = 0;UpdateData(FALSE);

file

菜单栏

资源视图,Menu
file

删除帮助以外的所有菜单栏
file

手动添加菜单
file

添加事件处理程序
个人信息
file
file

	::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_USER, NM_USER, 0);

file

销售管理
file

	::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_SELL, NM_SELL, 0);

file

库存信息
file

	::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_INFO, NM_INFO, 0);

file

库存添加
file

	::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_ADD, NM_ADD, 0);

file

库存删除
file

	::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), NM_DEL, NM_DEL, 0);

file

这样就可以通过菜单进行切换了
file

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com