基于MFC的餐饮点餐系统设计与实现

2020-11-25 01:52吴昊白俊鸽四川大学锦城学院计算机与软件学院
数码世界 2020年2期
关键词:菜谱数据包对话框

吴昊 白俊鸽 四川大学锦城学院 计算机与软件学院

1 背景

我国餐饮行业近年来发展迅速,今日的餐饮企业会同时管理多个餐饮品牌,同时单门店客户基数倍增。在激烈的市场竞争环境下,企业不仅需要创新产品,还需要创新企业模式理念。数字化点餐系统解决了传统模式中传菜员传达信息的时间延误,以及一旦忙起来传菜员可能会乱套的效率下降问题。

2 系统内容

本系统针对中小型餐饮团队,以中餐类目为示例,为经营中的点餐协作流程提供数字化的操作系统支持。具体为:为服务员提供下单系统、为后厨提供客人点菜流水清单和出菜流水清单、为管理者提供菜品编辑系统。

3 系统界面设计

3.1 总体设计

根据我们实地考察整理出的商家需求,我们将点餐系统分成三个界面,分别对应前台点餐、后台数据管理、厨房数据接收端。

3.2 前台菜谱下单系统设计

在前台菜谱下单系统,可以看到按照类目整理,能够直接点击交互的菜谱,和记录客人点的菜的点餐清单。并支持修改数量和口味,以及取消点好的菜品的功能。

3.3 厨房数据接收系统设计

厨房数据接收系统包含两个表格显示区,分别对应待完成的顾客点单和已完成的出菜流水。点击制作完成的菜品项,会弹出一个窗口校对详细菜品信息,确认无误后,点击[已完成,删除]按钮,菜品就会更新到“已完成菜品”表里。已完成菜品表也会按出菜顺序记录下菜品流水。

3.4 菜谱管理系统设计

该系统提供菜谱添加和菜谱修改菜单。添加菜品时会看到描述菜品属性的候选栏和输入框,对应菜品类别、菜品名称、菜品价格、菜品单位信息填写,点击[添加]按钮即可在总的菜谱中加入新菜品;同时支持清空和放弃选项。菜谱修改界面为菜谱总览和浏览视图,能在这里执行删除、修改功能。在总菜谱中找到对应的菜品,单击,右侧表格就会显示菜谱所有信息,输入框和候选栏中会显示出原有的菜品信息,提供编辑和删除功能。

4 功能实现

4.1 本例开发环境

本例使用VC++6.0进行开发,VC++6.0是一个代码编写和编译软件。全称为Visual C++6.0,是在Windows环境中工作的。在程序界面方面,我们选择MFC来实现这一目标。MFC是一个Windows应用程序开发模式,对程序的控制主要是由MFC框架完成的。对于信息传输,我们采用了TCP/IP协议簇中的socket套接字作为信息互通的方式。Socket套接字主要是描述IP地址和端口,目的在于实现不同计算机设备直接的网络通信。

为了方便演示,节省实际投入时的适配成本,本例使用本地文件来记录菜单数据,文件交互使用CFile来实现。Cfile类的CreateDirectory()、CopyFile()、DeleteFile()函数实现对文件的查找、复制、删除等操作。

4.2 前台菜谱下单系统实现

整个系统加载完成后,会将IDD_DIALDG_DISHCHOOSE对话框展示在使用者面前,同时读取存储在本地的DishMenuData文件,加载出菜谱。菜谱的实现使用MFC提供的CTreeCtrl类树形控件结构,先将菜品大类呈现给客户,点击类目会展开该类目的菜品。为了美观,此处会在菜品类目和菜品的文字前加载一个小图标以示区分,一共能展示给使用者三个不同的图标。实现为HICON hIcon创建图表句柄,imageList.Create(32,32,8,0,32)创建图像列表,hIcon[0]= AfxGetApp()->LoadIcon(IDI_ICON2)和 m_imageList.Add(hIcon[0])语句将图标加到图像列表中,m_MenuTree.SetImageList(&m_imageList,TVSIL_NORMAL)语句设置控件所使用的图像列表。这里的实现仅以一个图标举例,其它图标实现方法相同,只是文件名和存储地址不同,此处不再赘述。

统计表格我们使用CListCtrl来实现,通过CRect rect语句声明点菜清单区域,使用m_menuListCtl.GetWindowRect(&rect)语句获取窗体的边界矩形赋值给rect,实现点菜清单区域的划分;表格通过设置扩展风格dystyle|=LVS_EX_GRIDLINES实现;选中某行菜品后高亮显示由dwStyle|=LVS_EX_FULLROWSELECT实现;表头信息使用语句m_menuListCtl.InsertColumn(0,_T("菜名称"),LVCFMT_LEFT, (int)(rect.Width()*0.31))实现,此处以菜品的菜名属性举例,菜品的其他属性譬如单价、数量、单位、口味、金额等实现方法一致,以此类推。

这一交互是由双击后弹出的单独的对话框IDD_DLG_NUMCHANGE实现的,对话框里包含了口味候选框和数量输入框供用户修改。核心实现是由g_nItem识别出菜品,通 过 CDlgNumChange::strDisNum=m_menuListCtl.GetItemText(g_nItem,2)将口味和数量提供给用户进行交互。

当顾客确认点餐,点餐的内容我们使用SOCKET套接字来进行传输。由于本例仅作技术演示,传输的目的IP地址我们设置为本地地址127.0.0.1,用户能看到我们默认设置的IP,也能修改它,代码为((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->SetAddress(ntohl(inet_addr("127.0.0.1")))。关于传输过程,当用户点击确认发送按钮,并且在“您是否确定发送该顾客菜单?”对话框处点击确认后,会执行信息打包发送的步骤。代码实现为通过 for(int i=0;i<nCount; i++)实现将所有菜品按照相同方法打包,然后使用CString strName= m_menuListCtl.GetItemText(i,0)语句分别将菜品名称、菜品数量、菜品单位、菜品口味信息分别传入strName、strNum、strUnit、strTaste里。对于单个菜品报文,打包代码为strTemp+="#name="+strName+";num="+strNum+";unit="+strUnit+";

taste="+strTaste+ "@";这样的报文打包以#开头以@结尾,方便我们在内容整理的时候区分开每个数据包里的菜品信息。当所有菜品传输完成后,我们使用strTemp+="#end@";语句在整个菜品信息报文的末尾添加结束标志,方便在接收到的时候区分接受到的报文是来自一次点餐还是多次点餐。准备好了报文信息,还需要做的就是表头信息了。表头部分重点在于缓冲区的设置,此处操作我们使用strncpy函数。

同时,此处的SOCKET传输带有发送检测,成功与否都会提示用户。检测判别的方法是使用string库中的find()函数,这个函数会查找指定字符在母串中的位置,并将位置数据传入返回值,找不到目标字符的时候会返回标记npos。我们定义一个字符串起始标志indexBe和结束标志indexEnd,通过find函数搜索字符串的起始字符和结束字符,分别赋值给indexBe和indexEnd,再分别将其与传输数据串的npos比较,可以确定传输的成功与否,并出对话框提示。判定语句为 while (indexBe!=string::npos)和 if(indexEnd!=string::npos)。

4.3 厨房数据接收系统实现

厨房数据接收端会先展示系统中的IDD_DIALDG_KITCHEN对话框,这个对话框最重要的两部分:待完成流水表和已完成流水表也是由CListCtrl的扩展风格实现的,流水表的每一项菜品的参数数据使用STL容器中的MAP容器来装载。显示的信息是实时的,需要输入端传数据过来才看得到,实现是接受到数据以后使用我自己封装的StrIntoListCtl显示菜单函数。函数执行的内容主要为,先用InsertItem在控件中申请一行表格放数据,然后用SetItemText将内容填入,最后执行UpdateData刷新函数。这里我们使用了MFC自带的UpdateData刷新函数,由于我们需要在窗口中显示成员变量,也就是菜品的各项数据,所以我们将函数参数设为FALSE,FALSE的作用为,将接收到的数据展示到该窗口。

在socket接收时,由于发送方可能一次发很多包,也可能所有文件都发在一个包,但接收端接收时的看到的都是全部的包,有时候就会有各个包之间内容粘连的情况(俗称粘包)发生。对于这样的粘包问题,我们通过增加起始和结束字符的方法避免了。拆包时,先用if(retval==nPackLenght)和else if(retval>nPackLenght)语句判别我们收到包的情况。其中retval为我们接收到的字符串,而nPackLenght为数据包包长,通过这一组语句我们可以得知我们接收到的数据是来自单个包还是多个包。单个包直接导入就行,如果是来自多个包,那我们首先要整理数据包。整理数据包的具体过程为,首先计算数据包的个数,这个过程的核心是使用一个循环来查找数据包的起始标志字符#和结束字符@,并考虑end内容的判断,当我们查到一组有效内容就让记数文件nChNum+1,然后我们设置一个执行条件为(int i=0;i<nChNum;i++)的for循环,每一次执行只读取一个包长的数据,就成功的实现了socket包的拆解。

此外,由于本界面是一个未完成菜品和已完成菜品的流水页,对于同一客人点的某道菜品,其内容是同一个资源,所以当用户点击[已完成,删除]的按钮时,执行的内容是在未完成菜品中将菜品删除并刷新未完成菜品列表,并在已完成菜品中显示。实现方法为自定义的KitchenDelWait函数,核心功能是在删除未完成菜品的时候,就用一个类去记载删除菜品的信息,并使用与StrIntoListCtl函数类似的方法将菜品信息传入已完成流水。

4.4 菜谱管理系统实现

菜谱管理系统核心是菜谱添加窗口IDD_DIALDG_BGDATAADD和菜谱编辑窗口IDD_DIALDG_AMEND,用户点击此系统时会将两个对话框展示为同级菜单,同一时刻只能操作其中的一个。编辑窗口的界面和实现都与点菜窗口相似,但主要区别在于,点菜窗口的菜品主要用于展示,所以刷新函数UpdateData参数设置为FALSE,执行后会将菜谱文件中的信息展示到窗口;此处的窗口目的为修改信息,所以将刷新函数UpdateData参数设置为TRUE,执行后会将窗口中的信息写入菜谱文件。

菜谱添加窗口就只有两个候选栏、两个输入框、以及确认、清空、放弃按钮。这里可以看到菜品的类目,由于用户输入的数据可能会涉及程序的各种边界值,设置了各种可能涉及到的报错预警,例如if(""==strName)为未输入菜名,会弹对话框提醒用户输入等情况,通过报错条件判断结果的布尔值作为报错提示框的if函数参数值即可实现各类报错提示框。而当新菜品输入好以后,为新菜建立一个指针,然后将指针链接到链表的尾部即可,具体代码为m_dishMenu.AddTail(structDis)。

5 结语

虽然本次实现的餐饮管理系统已经能够实现整个点餐流程,但是站在产品的角度还可以做更多的完善,比如设立微信扫码点餐的信息接收接口,将付款流程也加入进系统等。在以后的学习中,除了代码本身,还可以多思考如何提升产品交互易用性。

猜你喜欢
菜谱数据包对话框
二维隐蔽时间信道构建的研究*
“吃”出乡村振兴广东幸福菜谱推新品
民用飞机飞行模拟机数据包试飞任务优化结合方法研究
Bootlace Worms’Secret etc.
What Is Beauty?
C#串口高效可靠的接收方案设计
菜谱
菜谱中的黑米粒儿
浅谈VB的通用对话框《CommonDialog》控件的使用
菜谱 经典菜翻花样