C++界面实现超市综合管理系统_vc++6.0mfc超市管理界面设计-程序员宅基地

项目背景

当今大学生由于多方面原因不能在自己的动手能力方面的到很多锻炼,大多数的知识来源于课本,这就导致很多大学生动手能力很差,在这样的背景下,学院和学校组织了实习,在实习中锻炼我们的能力,让我们学到的知识更加的扎实,让知识更具有应用能力。

项目描述

这是一个关于超市综合管理的一个系统其中包括两大部分,主要前台与后台,前台的主要功能就是具有传统收银台的收银功能,还具有队与超市会员信息管理的的功能,除增删查改之外,还增加了积分查询等功能,而后台是管理员操作界面,后台管理员的主要职责是队于员工信息进行增删查改,对于各类商品的进行管理其中包括(新商品入库、清除过期商品、修改商品信息、查询商品信息以及收银报表的查看)等功能。

项目设计

系统分为前台与后台,我们将项目细分为两个方面,首先我们要做一个有界面的系统,界面界面主要有登录界面、收银界面、管理员界面。登录界面,而设计数据存储的方面我们将会采用MySQL数据库进行存储。

准备阶段

由于我们之前所了解的C++知识很多偏向理论,而且偏向于后台服务器相关的内容,所以对于是实现界面的方面不是很了解,所以老师给我们推荐了一个外部库(DuiLib),通过这套库我们可以轻松实现一些简单界面的操作。但是由于引进的是一个外部库,所以我们要自行对库文件进行编译,我们的
项目主要开发环境是VS2017,对以前编译器功能的配置进行增加才能进行编译,在编译成功后会生成两个文件

环境配置

在编译完成后就需要生成的文件和DuiLib放到目标文件下,然后就是对于数据库的链接,在项目属性中选择链接和编译中找到数据库安装的路径,然后对于将include和lib文件分别添加到项目中,基本环境搭建就完成了。

模块划分

首先对于这给项目我们需要给我们的数据库中添加四张表,作为各方面数据的存储,便于后面的管理。其次我们需要做三个窗口,分别是登录窗口、管理员窗口以及收银台窗口。各个窗口实现的功能分别是,登录窗口实现区别前台收银人员与后台管理人进行区分,当不同身份的进行登录,进入的接面和功能都不同。管理员窗口需要实现连接数据库对人员商品信息进行各种操作,收银界面主要是对于商品销售的操作,可以连接数据库对商品相关的表进行操作,还有对于会员信息的表格,对于会员信息进行增删查改的操作,还要将其更新到销售记录中。

数据库的创建

登录数据库,创建cash数据库,将四张表格储存在其中。
在这里插入图片描述这就是存在数据库中的四张表。

数据库操作封装

由于我们以后很多操作都是界面操作,所以对于数据库我们不能数据一旦变动必须打开数据进行更新,所以我们要将数据库的增删查改操作进行封装,这样我们就可以在系统界面无论是人员信息或者商品信息进行了一些操作时就还可以让数据库实时更新。
首先我们先简历一个头文件MySQL.h对于要实现的功能进行罗列:
MySQL.h

#pragma once
#include <Winsock2.h>
#include <mysql.h>
#include <string>
#include <vector>
using namespace std;
class MySQL
{
public:
	MySQL();
	bool ConnectMySQL(const char* host, const char* user, const char* passward, const char* dbName);
	~MySQL();

	bool Insert(const string& strSQL);
	bool UpDate(const string& strSQL);
	bool Delete(const string& strSQL);
	vector<vector<string>> Select(const string& strSQL);
private:
	MYSQL* _mySQL;
};

我们要实现数据库的基本操作增删查改,所以罗列了以上四个功能Insert(插入)、UpData(更新)、Delete(删除)、Select(查找),通过构建一个cpp文件用mysql.h头文件中封装好的函数对于这些功能进行实现;
MySQL.cpp

#include "MySQL.h"
#include <iostream>
using namespace std;


MySQL::MySQL()
{
	_mySQL = mysql_init(nullptr);
}

bool MySQL:: ConnectMySQL(const char* host, const char* user, const char* passward, const char* dbName)
{
	if (!mysql_real_connect(_mySQL, host, user, passward, dbName, 3306, nullptr, 0))
	{
		cout << "数据库连接失败" << endl;
		return false;
	}

	mysql_query(_mySQL, "set names 'gbk'");
	return true;
}

vector<vector<string>> MySQL::Select(const string& strSQL)
{
	vector<vector<string>> vvRet;
	if (mysql_query(_mySQL, strSQL.c_str()))
	{
		// SQL命令响应失败
		cout << mysql_error(_mySQL) << endl;
		return vvRet;
	}

	// 获取查询的记录集
	MYSQL_RES * mySQLRes = mysql_store_result(_mySQL);
	if (nullptr == mySQLRes)
	{
		cout << mysql_error(_mySQL) << endl;
		return vvRet;
	}

	// 获取记录中有多少个字段
	int itemCount = mysql_num_fields(mySQLRes);
	MYSQL_ROW mysqlRow;

	while (mysqlRow = mysql_fetch_row(mySQLRes))
	{
		// 已经获取到一条记录
		vector<string> vItem;
		for (size_t i = 0; i < itemCount; ++i)
		{
			vItem.push_back(mysqlRow[i]);
		}

		vvRet.push_back(vItem);
	}

	mysql_free_result(mySQLRes);

	return vvRet;
}

bool MySQL::Insert(const string& strSQL)
{
	if (mysql_query(_mySQL, strSQL.c_str()))
	{
		// SQL命令响应失败
		cout << mysql_error(_mySQL) << endl;
		return false;
	}

	return true;
}

bool MySQL::UpDate(const string& strSQL)
{
	if (mysql_query(_mySQL, strSQL.c_str()))
	{
		// SQL命令响应失败
		cout << mysql_error(_mySQL) << endl;
		return false;
	}

	return true;
}

MySQL::~MySQL()
{
	mysql_close(_mySQL);
}

以上代码核心就是运用mysql_query函数,这个函数有两个参数,第一个是数据库操作句柄MYSQL类型可以通过句柄来对数据库进行操作,第二个是我们所构造的SQL语句,就是我们自己数据库中对表进行的操作。

界面实现

关于DuiLib
Duilib 界面库使用介绍 一、Duilib 简介 Duilib 是以 DirectUI 为技术原理开发的一款轻量级 Windows 桌面 UI 库,具有入门简单,使用方便等特点,在国内吸引了不少的开发者。其开发原型为国外大神viksoe 的 http://www.viksoe.dk/code/windowless1.htm 文章中提供的源码,国内开源前辈以此为基础:修正 Bug、优化程序结构、提高稳定性和易用性,是一款功能强大,使用方便的界面库。 界面库使用 XML 来描述界面风格,界面布局,可以很方便的构建高效,绚丽的,非常易于扩展的界面。从而很好的将界面和逻辑分离,同时易于实现各种超炫的界面效果如换色,换肤,透明等。 Duilib 界面库的出现解决了使用传统 MFC 界面库开发软件不美观、界面细节处理不好、使用硬编码、开发效率低下、生成程序体积大等问题。
具体使用介绍: https://www.cnblogs.com/Alberl/p/3354459.htmlhttps://www.cnblogs.com/Alberl/p/3354459.html
为什么选择这个库?
1.开源
2.界面制作有特有工具
3.可以用比较简单的方式生成美观的界面
4.开发效率高
登录窗口
该界面中有两个输入框和三个按钮组成,输入框分别是员工姓名和密码,对应数据库表中name和password,三个按钮分别是登录、最小化窗口、关闭窗口。由于提供了设计工具所以对于界面所有的地方都可以进行个性化设计这是这是我设计的登录界面,用设计工具将接麦你设计完成后,进行保存会生成一个.xml文件,后面在程序中会用到这个文件,所以一定要将它的路径记住。
与数据库操作相同我们先创建一个头文件将需要的操作罗列出来
LogLnWnd.h`



class LogInWnd : public WindowImplBase
{
public:
	LogInWnd(MySQL* pMySQL);

	virtual void Notify(TNotifyUI& msg);

	void LogIn();
protected:
	// WindowImplBase:提供的三个纯虚函数
	// xml文件对应的目录
	virtual CDuiString GetSkinFolder();

	// xml文件的名字
	virtual CDuiString GetSkinFile();

	// 窗口类的名字:在注册窗口时必须提供
	virtual LPCTSTR GetWindowClassName(void) const;

	MySQL* m_pMySQL;
};

我们通过Notify这个函数对通过DuiLIb提供的TNotifyUI& msg这个变量对鼠标点击的信息进行捕获,这个窗口主要的功能就是登录,通过捕获按钮的被鼠标点击的名字进行相应操作具体实现在LogInWnd.cpp
#include “MainWnd.h”
#include “CashierWnd.h”

LogInWnd::LogInWnd(MySQL* pMySQL)
m_pMySQL(pMySQL)
{}

// xml文件对应的目录
CDuiString LogInWnd::GetSkinFolder()
{
return _T("");
}

// xml文件的名字
CDuiString LogInWnd::GetSkinFile()
{
return _T(“loginWnd.xml”);
}

// 窗口类的名字:在注册窗口时必须提供
LPCTSTR LogInWnd::GetWindowClassName(void) const
{
return _T(“LogInWnd”);
}

void LogInWnd::Notify(TNotifyUI& msg)
{
CDuiString strName = msg.pSender->GetName();
if (msg.sType == _T(“click”))
{
if (strName == _T(“BTN_MIN”))
::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
//SendMessage(WM_SYSCOMMAND,SW_MINIMIZE);
else if (strName == _T(“BTN_CLOSE”))
Close();
else if (strName == _T(“BTN_LOGIN”))
LogIn();
}
}

void LogInWnd::LogIn()
{
// 从编辑框中获取用户名以及密码
CEditUI* pEditUserName = (CEditUI*)m_PaintManager.FindControl(_T(“EDIT_USER_NAME”));
CDuiString strUserName = pEditUserName->GetText();

CEditUI* pEditPassword = (CEditUI*)m_PaintManager.FindControl(_T("EDIT_USER_PASSWORD"));
CDuiString strUserPassWord = pEditPassword->GetText();

if (strUserName.IsEmpty())
{
	MessageBox(m_hWnd, _T("请输入用户名"), _T("Cashier"), IDOK);
	return;
}

if (strUserPassWord.IsEmpty())
{
	MessageBox(m_hWnd, _T("请输入用户密码"), _T("Cashier"), IDOK);
	return;
}

// 查询数据库,检测该用户是否存在
string strSQL("select * from  employee where Name = '");
// ascII   UNICODE
strSQL += UnicodeToANSI(strUserName);
strSQL += "';";

vector<vector<string>> vRet = m_pMySQL->Select(strSQL);
if (vRet.empty())
{
	MessageBox(m_hWnd, _T("用户名错误"), _T("Caisher"), IDOK);
	return;
}

string userpassward = UnicodeToANSI(strUserPassWord);
if (userpassward != vRet[0][4])
{
	MessageBox(m_hWnd, _T("用户密码错误"), _T("Caisher"), IDOK);
	return;
}

// 隐藏登录窗口
ShowWindow(false);

if (vRet[0][5] == "管理员")
{
	// 创建主窗口
	MainWnd mianWnd(m_pMySQL);
	mianWnd.Create(NULL, _T("MainWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
	mianWnd.CenterWindow();
	mianWnd.ShowModal();
}
else
{
	// 创建主窗口
	CCashierWnd mianWnd(m_pMySQL);
	mianWnd.Create(NULL, _T("CashierWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
	mianWnd.CenterWindow();
	mianWnd.ShowModal();
}}

通过我们对于每个按钮名字都进行了命名,所以我们可以实现对每个按钮的点击进行捕获,有两个可以重复只用就是关闭和最小化,对于登陆我们需要对人员身份进行区分,如果登录人员是管理员就需要打开管理员的界面,如果登录信息是售货员就需打开售货员的界面,所以我们就需要对数据库的数据进行查找通过返回的字符串型二维数组进行身份比较,得出登录人员的身份。
管理员界面
这是一个由若干输入框和下拉表,以及对个按钮实现,由于管理员进行的操作十分复杂,所以我们的界面也更加复杂,这个界面可以实现对所有人员的信息进行增删查改,并且将查到的结果输出到界面上,还可以对
商品进行的信息进行更改,最后对于所有界面上的操作如果涉及到超市人员或者商品信息的变动我们都将会把它放入我们的数据库中。
在这里插入图片描述
首先我们还是创建一个头文件对所需要的功能及进行罗列和函数生明Mainwnd.h`

#pragma once

#include "Common.h"

class MainWnd : public WindowImplBase
{
public:
	MainWnd(MySQL* pMySQL);
	~MainWnd();

	virtual void Notify(TNotifyUI& msg);

protected:
	// WindowImplBase:提供的三个纯虚函数
	// xml文件对应的目录
	virtual CDuiString GetSkinFolder();

	// xml文件的名字
	virtual CDuiString GetSkinFile();

	// 窗口类的名字:在注册窗口时必须提供
	virtual LPCTSTR GetWindowClassName(void) const;

	void SelectEmployeeInfo();

	void DeleteEmployeeInfo();

	void InsertEmployeeInfo();

private:
	MySQL* m_pMySQL;
};

首先前面三个函数是继承自父类,所以前面相同,我们需要实现的使对人员信息的增删查改,所以我们需要建立一个cpp文件来对函数进行实现Maind.cpp

#include "MainWnd.h"


MainWnd::MainWnd(MySQL* pMySQL)
: m_pMySQL(pMySQL)
{
}

MainWnd::~MainWnd()
{

}

// xml文件对应的目录
CDuiString MainWnd::GetSkinFolder()
{
	return _T("");
}

// xml文件的名字
CDuiString MainWnd::GetSkinFile()
{
	return _T("MainWnd.xml");
}

// 窗口类的名字:在注册窗口时必须提供
LPCTSTR MainWnd::GetWindowClassName(void) const
{
	return _T("MainWnd");
}

void MainWnd::Notify(TNotifyUI& msg)
{
	CDuiString strName = msg.pSender->GetName();
	if (msg.sType == _T("click"))
	{
		if (strName == _T("BTN_CLOSE"))
			PostQuitMessage(0); //Close();
		else if (strName == _T("BTN_MIN"))
			::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
		else if (strName == _T("BTN_SELECT"))
			SelectEmployeeInfo();
		else if (strName == _T("BTN_INSERT"))
			InsertEmployeeInfo();
		else if (strName == _T("BTN_UPDATE"))
			MessageBox(NULL, _T("UpdateBTN"), _T("Cashier"), IDOK);
		else if (strName == _T("BTN_DELETE"))
			DeleteEmployeeInfo();
		else if (strName == _T("BTN_SELL_RECORD"))
			MessageBox(NULL, _T("SELLBTN"), _T("Cashier"), IDOK);
	}
	else if (msg.sType == _T("selectchanged"))
	{
		CTabLayoutUI* pTab = (CTabLayoutUI*)m_PaintManager.FindControl(_T("tablayout"));
		if (strName == _T("OPTION_EMPLOYEE"))
			pTab->SelectItem(0);
		else
			pTab->SelectItem(1);
	}
	else if (msg.sType == _T("windowinit"))
	{
		// 窗口在创建期间,将一些空间初始化
		CComboBoxUI* pGender =  (CComboBoxUI*)m_PaintManager.FindControl(_T("usergender"));
		pGender->SelectItem(0);

		CComboBoxUI* pPosition = (CComboBoxUI*)m_PaintManager.FindControl(_T("position"));
		pGender->SelectItem(0);

		CComboBoxUI* pSelect = (CComboBoxUI*)m_PaintManager.FindControl(_T("COMOB_SELECT"));
		pSelect->SelectItem(0);
	}
}

void MainWnd::SelectEmployeeInfo()
{
	string strSQL("select * from employee");

	CComboBoxUI* pCombo = (CComboBoxUI*)m_PaintManager.FindControl(_T("COMOB_SELECT"));
	CDuiString strStyle = pCombo->GetText();
	if (strStyle == _T("无"))
		strSQL += ";";
	else if (strStyle == _T("名字"))
	{
		strSQL += " where Name = '";
		CDuiString strName = ((CEditUI*)m_PaintManager.FindControl(_T("username")))->GetText();
		if (strName.IsEmpty())
		{
			MessageBox(m_hWnd, _T("请输入查询用户的名字"), _T("Cashier"), IDOK);
			return;
		}

		strSQL += UnicodeToANSI(strName);
		strSQL += "';";
	}
	else if (strStyle == _T("性别"))
		;
	else if (strStyle == _T("薪资"))
		;

	vector<vector<string>> vRet = m_pMySQL->Select(strSQL);
	if (vRet.empty())
		return;

	CListUI* pListUI = (CListUI*)m_PaintManager.FindControl(_T("ListEmployeeInfo"));
	pListUI->RemoveAll();

	for (size_t i = 0; i < vRet.size(); ++i)
	{
		vector<string>& strItem = vRet[i];
		CListTextElementUI* pData = new CListTextElementUI;
		pData->SetAttribute(_T("align"), _T("center"));
		
		pListUI->Add(pData);
		
		// 名字
		pData->SetText(0, ANSIToUnicode(strItem[1]));
		pData->SetText(1, ANSIToUnicode(strItem[2]));
		pData->SetText(2, ANSIToUnicode(strItem[3]));
		pData->SetText(3, ANSIToUnicode(strItem[5]));
		pData->SetText(4, ANSIToUnicode(strItem[6]));
		pData->SetText(5, ANSIToUnicode(strItem[7]));		
	}
}

void MainWnd::DeleteEmployeeInfo()
{
	// 获取当前选中
	CListUI* pListUI = (CListUI*)m_PaintManager.FindControl(_T("ListEmployeeInfo"));
	int lineNo = pListUI->GetCurSel();
	CListTextElementUI* pRow = (CListTextElementUI*)pListUI->GetItemAt(lineNo);

	// 从数据库中将该员工的信息删除
	// 构造SQL命令;
	string strSQL("delete ");

	CDuiString strName = pRow->GetText(0);

	// 从数据库中将该条记录删除
	//m_pMySQL->Delete(strSQL);

	// 从List中移除
	pListUI->RemoveAt(lineNo);
}

void MainWnd::InsertEmployeeInfo()
{
	// 从界面中获取员工信息
	CDuiString strName = ((CEditUI*)m_PaintManager.FindControl(_T("username")))->GetText();
	CDuiString strGender = ((CComboBoxUI*)m_PaintManager.FindControl(_T("usergender")))->GetText();
	CDuiString strBirthday = ((CEditUI*)m_PaintManager.FindControl(_T("userbirthday")))->GetText();
	CDuiString strPosition = ((CComboBoxUI*)m_PaintManager.FindControl(_T("position")))->GetText();
	CDuiString strTel = ((CEditUI*)m_PaintManager.FindControl(_T("telphone")))->GetText();
	CDuiString strSalary = ((CEditUI*)m_PaintManager.FindControl(_T("salary")))->GetText();
	
	CListUI* pListUI = (CListUI*)m_PaintManager.FindControl(_T("ListEmployeeInfo"));
	char szCount[32] = { 0 };
	_itoa(pListUI->GetCount()+1, szCount, 10);
	// 构造SQL命令
	string strSQL("insert into employee values(");
	strSQL += szCount;
	strSQL += ",'";
	strSQL += UnicodeToANSI(strName);
	strSQL += "','";
	strSQL += UnicodeToANSI(strGender);
	strSQL += "','";
	strSQL += UnicodeToANSI(strBirthday);
	strSQL += "','000000','";
	strSQL += UnicodeToANSI(strPosition);
	strSQL += "','";
	strSQL += UnicodeToANSI(strTel);
	strSQL += "','";
	strSQL += UnicodeToANSI(strSalary);
	strSQL += "');";

	// 响应SQL命令
	m_pMySQL->Insert(strSQL);

	// 将该员工的信息插入到List
	CListTextElementUI* pItem = new CListTextElementUI;
	pListUI->Add(pItem);
	pItem->SetText(0, strName);
	pItem->SetText(1, strGender);
	pItem->SetText(2, strBirthday);
	pItem->SetText(3, strPosition);
	pItem->SetText(4, strTel);
	pItem->SetText(5, strSalary);
}

这段代码前三个函数是对于窗口以及初始化,后面利用构建SQL语句来实现对于数据库的操作,这个函数的主体还是一个按钮操作,通过鼠标对于不同按钮的点击就可以实现执行不同操作,后面的函数实现,就只操作的具体实现步骤首先讲插入
1.在界面的输入框输入的内容进行捕获:CDuiString strName = ((CEditUI*)m_PaintManager.FindControl(_T(“username”)))->GetText();
2.对下拉链表的内容进行捕获CDuiString strGender = ((CComboBoxUI*)m_PaintManager.FindControl(_T(“usergender”)))->GetText();
3.对于点击消息进行捕获: CDuiString strName = msg.pSender->GetName();
通过捕获来自不同按钮的捕获我们就可以实现响应不同的消息,并将响应消息与数据库结合起来,从而达到前台与有台同步数据
售货员界面
这个界面主要工鞥能就是收银和对于会员信息的管理,界面设置主要是,一个输入框和部分按钮组成分别用作输入和查询,还有出售商品的计价操作商品数量的操作,我们首先将这些操作进行声明,创建一个头文件
在这里插入图片描述
CashierWnd.h

#pragma once
#include "Common.h"

class CCashierWnd : public WindowImplBase
{
public:
	CCashierWnd(MySQL* pMySQL);
	~CCashierWnd();

	virtual void Notify(TNotifyUI& msg);

protected:
	// WindowImplBase:提供的三个纯虚函数
	// xml文件对应的目录
	virtual CDuiString GetSkinFolder();

	// xml文件的名字
	virtual CDuiString GetSkinFile();

	// 窗口类的名字:在注册窗口时必须提供
	virtual LPCTSTR GetWindowClassName(void) const;

	void SelectGoods();
	void AddGoodsCount();
	void SubGoodsCount();
	void InsertGoodsList();
	void CancelOrder();
	void CommitOrder();
private:
	MySQL* m_pMySQL;
};


我们创建一个cpp文件将这些操作进行具体实现

#include "CashierWnd.h"


CCashierWnd::CCashierWnd(MySQL* pMySQL)
: m_pMySQL(pMySQL)
{
}


CCashierWnd::~CCashierWnd()
{
}


// xml文件对应的目录
CDuiString CCashierWnd::GetSkinFolder()
{
	return _T("");
}

// xml文件的名字
CDuiString CCashierWnd::GetSkinFile()
{
	return _T("CashierManage.xml");
}

// 窗口类的名字:在注册窗口时必须提供
LPCTSTR CCashierWnd::GetWindowClassName(void) const
{
	return _T("CashierWnd");
}

void CCashierWnd::Notify(TNotifyUI& msg)
{
	CDuiString strName = msg.pSender->GetName(); 
	if (msg.sType == _T("click"))
	{
		if (strName == _T("BTN_CLOSE"))
			Close();
		else if (strName == _T("BTN_MIN"))
			::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
		else if (strName == _T("BTN_ADD"))
			AddGoodsCount();
		else if (strName == _T("BTN_SUB"))
			SubGoodsCount();
		else if (strName == _T("BTN_SELECT"))
			SelectGoods();
		else if (strName == _T("BTN_COMMIT"))
			CommitOrder();
		else if (strName == _T("BTN_CANCEL"))
			CancelOrder();
		else if (strName == _T("BTN_OK"))
			InsertGoodsList();
	}
}

void CCashierWnd::SelectGoods()
{
	// 1. 获取商品名称
	CDuiString strGoodsName = ((CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_NAME")))->GetText();

	// 2. 构造SQL语句,到数据库中查此商品
	string strSQL("select * from goodstable where GoodsName = '");
	strSQL += UnicodeToANSI(strGoodsName);
	strSQL += "';";
	vector<vector<string>> vRet = m_pMySQL->Select(strSQL);
	if (vRet.empty())
	{
		MessageBox(m_hWnd, _T("暂无此商品"), _T("Cashier"), IDOK);
		return;
	}

	// 3. 将商品剩余个数显示到界面编辑框中
	((CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_LEFT")))->SetText(ANSIToUnicode(vRet[0][7]));
}

void CCashierWnd::AddGoodsCount()
{
	// 库存减1
	CEditUI* pGoodsLeft = (CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_LEFT"));
	CDuiString strLeft = pGoodsLeft->GetText();
	if (strLeft == _T("0"))
	{
		MessageBox(m_hWnd, _T("库存量不足"), _T("Cashier"), IDOK);
		return;
	}

	int count = 0;
	count = atoi(UnicodeToANSI(strLeft).c_str());
	--count;
	strLeft.Format(_T("%d"), count);
	pGoodsLeft->SetText(strLeft);

	// 商品个数加1
	CEditUI* pGoodsCount = (CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_COUNT"));
	CDuiString strCount = pGoodsCount->GetText();
	count = atoi(UnicodeToANSI(strCount).c_str());
	++count;
	strCount.Format(_T("%d"), count);
	pGoodsCount->SetText(strCount);
}

void CCashierWnd::SubGoodsCount()
{
	// 商品个数减去1
	CEditUI* pGoodsCount = (CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_COUNT"));
	CDuiString strCount = pGoodsCount->GetText();
	if (strCount == _T("0"))
	{
		MessageBox(m_hWnd, _T("商品个数已经为0!!!"), _T("Cashier"), IDOK);
		return;
	}

	int count = atoi(UnicodeToANSI(strCount).c_str());
	--count;
	strCount.Format(_T("%d"), count);
	pGoodsCount->SetText(strCount);

	// 库存减1
	CEditUI* pGoodsLeft = (CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_LEFT"));
	CDuiString strLeft = pGoodsLeft->GetText();	
	count = atoi(UnicodeToANSI(strLeft).c_str());
	++count;
	strLeft.Format(_T("%d"), count);
	pGoodsLeft->SetText(strLeft);
}

void CCashierWnd::InsertGoodsList()
{
	// 1. 从界面获取商品名称以及购买的数量
	CDuiString strGoodsName = ((CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_NAME")))->GetText();
	CEditUI* pGoodsCount = (CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_COUNT"));
	CDuiString strCount = pGoodsCount->GetText();
	
	// 2. 从数据库中获取商品的价格以及计量单位
	string strSQL("select * from goodstable where GoodsName = '");
	strSQL += UnicodeToANSI(strGoodsName);
	strSQL += "';";
	vector<vector<string>> vRet = m_pMySQL->Select(strSQL);

	// 3. 合计价格
	int count = atoi(UnicodeToANSI(strCount).c_str());
	double price = atof(vRet[0][5].c_str());
	price = count*price;
	CDuiString strPrice;
	strPrice.Format(_T("%lf"), price);

	// 4. 将信息更新到list中
	CListTextElementUI* pItem = new CListTextElementUI;
	CListUI* pList = (CListUI*)m_PaintManager.FindControl(_T("OrderList"));
	pList->Add(pItem);
	pItem->SetText(0, strGoodsName);
	pItem->SetText(1, ANSIToUnicode(vRet[0][5]));
	pItem->SetText(2, strCount);
	pItem->SetText(3, ANSIToUnicode(vRet[0][6]));
	pItem->SetText(4, strPrice);

	// 5. 将商品数量以及名称的编辑框清0
	((CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_NAME")))->SetText(_T(""));
	((CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_LEFT")))->SetText(_T(""));
	((CEditUI*)m_PaintManager.FindControl(_T("EDIT_GOODS_COUNT")))->SetText(_T("0"));
}

void CCashierWnd::CancelOrder()
{
	// 清空所有商品
	CListUI* pList = (CListUI*)m_PaintManager.FindControl(_T("OrderList"));
	pList->RemoveAll();
}

void CCashierWnd::CommitOrder()
{
	// 1. 合计总价格
	CListUI* pList = (CListUI*)m_PaintManager.FindControl(_T("OrderList"));
	int count = pList->GetCount();

	double totalPrice = 0;
	for (int i = 0; i < count; ++i)
	{
		CListTextElementUI* pItem = (CListTextElementUI*)pList->GetItemAt(i);
		CDuiString strPrice = pItem->GetText(4);
		totalPrice += atof(UnicodeToANSI(strPrice).c_str());
	}

	CDuiString strTotalPrice;
	strTotalPrice.Format(_T("%.02lf"), totalPrice);
	((CEditUI*)m_PaintManager.FindControl(_T("EDIT_TOTAL")))->SetText(strTotalPrice);
	// 2. 更新商品的数据库
	for (int i = 0; i < count; ++i)
	{
		CListTextElementUI* pItem = (CListTextElementUI*)pList->GetItemAt(i);
		CDuiString strCount = pItem->GetText(2);

		string strSQL("update goodstable set Inventory='");
		strSQL += UnicodeToANSI(strCount);
		strSQL += "';";
		m_pMySQL->UpDate(strSQL);
	}
	// 3. 插入本次销售记录
}

这个界面的所有操作与管理员界面的操作类似,有按钮等构成,通过按钮相应不同的功能,调用不同的函数,也是通过构造SQL语句,操作数据库,从而达到改变数据库内部的数据

其他函数

这个项目就像是,一栋房子,不仅有大框架还有一些基本每个头文件都会用到的函数我们来创建一个头文件来包含它
common.h

#pragma once



#include <UIlib.h>
using namespace DuiLib;

#include "MySQL.h"

#ifdef _DEBUG
#   ifdef _UNICODE
#       pragma comment(lib, "DuiLib_ud.lib")
#   else
#       pragma comment(lib, "DuiLib_d.lib")
#   endif
#else
#   ifdef _UNICODE
#       pragma comment(lib, "DuiLib_u.lib")
#   else
#       pragma comment(lib, "DuiLib.lib")
#   endif
#endif


string UnicodeToANSI(const CDuiString& str);
CDuiString ANSIToUnicode(const string& str);


UnicodeToANSI将编码格式转化为二进制,ANSIToUnicode是将编码格式转化为Unicode格式我们会在后面具体实现common.cpp

#include "Common.h"


string UnicodeToANSI(const CDuiString& str)
{
	char*     pElementText;
	int    iTextLen;
	// wide char to multi char
	iTextLen = WideCharToMultiByte(CP_ACP,
		0,
		str.GetData(),
		-1,
		NULL,
		0,
		NULL,
		NULL);
	pElementText = new char[iTextLen + 1];
	memset((void*)pElementText, 0, sizeof(char)* (iTextLen + 1));
	::WideCharToMultiByte(CP_ACP,
		0,
		str.GetData(),
		-1,
		pElementText,
		iTextLen,
		NULL,
		NULL);
	string strText;
	strText = pElementText;
	delete[] pElementText;
	return strText;
}

CDuiString ANSIToUnicode(const string& str)
{
	int  len = 0;
	len = str.length();
	int  unicodeLen = ::MultiByteToWideChar(CP_ACP,
		0,
		str.c_str(),
		-1,
		NULL,
		0);
	wchar_t *  pUnicode;
	pUnicode = new  wchar_t[unicodeLen + 1];
	memset(pUnicode, 0, (unicodeLen + 1)*sizeof(wchar_t));
	::MultiByteToWideChar(CP_ACP,
		0,
		str.c_str(),
		-1,
		(LPWSTR)pUnicode,
		unicodeLen);
	CDuiString  rt(pUnicode);
	delete  pUnicode;
	return  rt;
}

项目中遇到的问题

1.首先环境搭建,如果连接文件有误,或者编译文件出现错误没有生成目标文件
可以已通过报错返回的错误类型如果外部库或者数据库头文件等就是存在环境搭建问题
2.类型转化问题?
很多时候需要将Unicode格式的编码转化为二进制或者将二进制转化为Uicode我们在网上查阅了相关资料编写了相关函数
3.SQL语句编写出错

项目总结

首先给我的收获就是学会了Duillib这套库的使用,可以制作简单的界面,让我学到了很多界面设计的知识其次我们学会了将自己的在一个项目中,自己会的语言并不是简单的进行组合,更要有大局观,要用语言将所有模块统一组织,更加注重模块之间的关系,而不思简单的对于语言的利用整个项目到这里就差不多了,整个项目从开始到结束历时一个周左右,部分功能可能还有待扩展,但是节本框架完善,可以进行基本操作,在这次项目中让我们学到的知识更加能够利用起来,更加明了,纸上得来终觉浅绝知此事要躬行,在今天我们应届大学生将会是今后社会上的中流砥柱,更加是社会未来的主人,不能只学课本上的知识,更加要将书本与实际相结合,做一个理论素质强,同时兼具动手能力的新时代大学生,才能更好面对将来的挑战。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_35689566/article/details/100240000

智能推荐

数据结构和算法之《栈》详解_csdn 栈-程序员宅基地

文章浏览阅读1.1k次,点赞54次,收藏29次。本文章详细讲述的栈的概念、结构和思路及代码的实现。零基础也可学!!!!!!详解包您理解到位!!!!!!同时头从栈中取出元素的例子解析,快来看吧。_csdn 栈

IntelliJ IDEA 中自动生成 serialVersionUID 的方法_idea自动生成serialversionuid-程序员宅基地

文章浏览阅读2.2k次。幸运的是,IntelliJ IDEA 提供了一种自动生成 serialVersionUID 的方法,可以帮助我们简化这个过程。通过使用 IntelliJ IDEA 的自动生成功能,我们在类的定义行上右键单击并选择 “Generate”,然后选择 “Serializable class”,IntelliJ IDEA 将自动生成 serialVersionUID 字段。生成的 serialVersionUID 是基于类的结构和成员的哈希值计算得出的,因此在类的结构发生变化时,生成的值也会相应地发生变化。_idea自动生成serialversionuid

java智慧导诊系统源码,可应用于微信线上挂号、互联网医院、区域平台-程序员宅基地

文章浏览阅读85次。智慧导诊针对具体医院业务场景可接入科室介绍,专家介绍,门诊安排,就诊需知, 科室位置等,患者选择科室后可直接完成挂号。智慧导诊系统按照人体的性别差异,设计了男性/女性两种3D立体模型,用于病症库与自助导诊之间数据信息的读取与交互,在软件病症库中,将不同患者的常见病症进行分类整合,患者可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室,为患者提供直观就医指导,减少导诊台工作量。4、根据患者提供的信息,会根据情况提供相关建议,并最终推荐就诊的科室。1)实现患者自助、正确的导诊,提高挂号窗口的速度;

设置vim 显示行号及快速定位_vim显示行号-程序员宅基地

文章浏览阅读990次。【代码】设置vim 显示行号及快速定位。_vim显示行号

MATLAB——生成周期序列_用 matlab 绘制周期矩阵序列,周期为 n ,每个周期内非零值点数为2m+1-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏7次。MATLAB——绘制离散周期信号_用 matlab 绘制周期矩阵序列,周期为 n ,每个周期内非零值点数为2m+1

在ncnn上把玩mobileNet_ncnn mobilenet-程序员宅基地

文章浏览阅读1.6w次。ncnn是腾讯优图最近开源的适合移动端的深度学习框架。mobileNet是谷歌在2017年4月份发表的论文MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications中提出的网络。_ncnn mobilenet

随便推点

Java项目基于ssm+vue.js的学生宿舍维修服务平台附带文章和源代码设计说明文档ppt-程序员宅基地

文章浏览阅读586次,点赞23次,收藏30次。博主介绍:CSDN特邀作者、985计算机专业毕业、某互联网大厂高级全栈开发程序员、码云/掘金/华为云/阿里云/InfoQ/StackOverflow/github等平台优质作者、专注于Java、小程序、前端、python等技术领域和毕业项目实战,以及程序定制化开发、全栈讲解、就业辅导、面试辅导、简历修改。精彩专栏 推荐订阅2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选题推荐2023-2024年最值得选的Java毕业设计选题大全:500个热门选题推荐。

ultralytics的YOLOv8改为自用版本_from ultralytics.utils.plotting import annotator, -程序员宅基地

文章浏览阅读944次。由于需要用pyqt给yolov8做一个界面,而ultralytics一层嵌一层,不是很好用,所以对它的这个源码进行精简,具体代码我放到了这里,ultralytics使用的版本是8.0.54。具体代码如下,需要根据自己的情况来修改data的配置文件以及权值文件,在代码的49和50行。_from ultralytics.utils.plotting import annotator, colors, save_one_box modul

c++陈维兴第三版3.35_C++面向对象程序设计教程第3版—陈维兴,林小茶课后习题答案...-程序员宅基地

文章浏览阅读1.1k次。C++面向对象程序设计教程课后题答案1、1什么就是面向对象程序设计?面向对象程序设计就是一种新的程序设计范型、这种范型的主要特征就是:程序=对象+消息面向对象程序的基本元素就是对象。主要结构特点就是:第一,程序一般由类的定义与类的使用两部分组成;第二,程序中的一切操作都就是通过向对象发送消息来实现的。1、2什么就是对象?什么就是类?对象与类之间的关系就是什么?对象就是描述其属性的数据以及对这些数据..._c++面向对象程序设计 陈维兴,林小茶课后习题

uniapp怎么引入css_uni-app关于自定义iconfont 本地引入 和 线上引入的两种方式-程序员宅基地

文章浏览阅读993次。前言写这个文章原因就是 要考虑uni-app打包成ios或android -app调试离线情况下线上引入icon无法显示的原因;就是uni-app iconfont离线引入本地引入一、自定义iconfont阿里巴巴矢量图标库https://www.iconfont.cn,创建项目,查找图标加入购物车后添加进自建项目内二、线上引用 先点刷新提示红字后刷新在线代码,然后将代码复..._uniapp加载在线css

如何 vscode 文件标签栏多行显示?_vscode标签页多行-程序员宅基地

文章浏览阅读2.5k次,点赞4次,收藏8次。如何 vscode 文件标签栏多行显示?步骤:ctrl + shift + p输入:open workspace settings搜索:wrap勾选:wrap tabs设置之后 第二次打开vscode 还是回一行文件名显示解决办法是:将这个设置写入配置json文件ctrl + shift + p输入:open workspace settings(JSON)添加配置,配置可通过配置界面操作得到{ // add at end "workbench.editor_vscode标签页多行

列表是不是python数据类型的是_在Python中,一个列表中的数据类型是否可以不相同?(回答可以or不可以)...-程序员宅基地

文章浏览阅读299次。【单选题】Western Nebraska generally receives less snow than _______ Eastern Nebraska.【论述题】请同学们录制一段1分钟左右的课文朗读(中英文均可),给这段声音配上适合的背景音乐,将这两段音乐合成后保存为MP3格式,以学号后五位+姓名命名,以附件形式上传。【简答题】请把上面这首诗翻译成一首现代诗。注意从音韵、措辞、修辞手法等..._some students prefer to spend their time taking part time jobs

推荐文章

热门文章

相关标签