电子点菜系统的分析、设计与实现本实验项目是为了综合运用嵌入式数据库、网络通信及嵌入式图形界面。
系统采用C/S 结构,实现简单的基于以太网的点菜系统。
将嵌入式开发板ARM2410S 作为服务器置于厨房,存储菜品并显示点菜情况;PC 机作为客户端,显示菜品信息和房间占用信息,服务员根据顾客的需求在客户端上选择房间并为顾客点菜,顾客用完餐后服务员在客户端更新房间占用情况。
系统结构如图1所示。
图0 电子点菜系统结构1 需求分析 1.1数据流图1.1.1 “电子点菜系统”顶级(0级)数据流图图1-1 顶级数据流图1.1.2 “电子点菜系统”1级数据流图就餐信息表 服务器 客户端图1-2 “电子点菜系统”1级数据流图1.1.3 “电子点菜系统”2级数据流图图1-3 “客户端”数据流图菜品及房间信息退房房间名就餐信息表图1-4 “服务器端”数据流图1.2 数据字典表1-1 数据字典1.3 “转换”的说明(1)显示空房间及菜品功能:显示可用房间的列表;显示所有菜品的列表,包括菜品名称、单价(2)开台/点菜功能:服务员根据可用房间列表的提示为顾客选定一个房间,并为顾客选择菜品(3)显示就餐信息功能:显示通过本客户端选了哪些房间以及每个房间点了哪些菜品(4)结帐功能:重新将某个房间置为可用状态(5)客户端收发数据功能:通过以太网收发客户端的数据(6)服务器端收发数据功能:通过以太网收发服务器端的数据(7)更新房间状态功能:将指定房间号的状态更改为指定状态(8)查询数据功能:从房间数据库读取房间记录,从菜品数据库读取菜品的记录,输出其它转换所需要的数据(9)显示房间及其菜品表功能:显示选用房间及该房间顾客所点菜品名称2 概要设计2.1 客户端功能模块层次结构图2-1 客户端功能模块层次结构图2.2 服务器端功能模块层次结构图2-2 客户端功能模块层次结构图3 详细设计3.1 界面设计3.1.1 客户端界面设计(1)初始界面启动后弹出图3-1所示界面。
图3-1 客户端初始界面“点菜”按钮的程序流程如图3-2所示。
图3-2 “点菜”按钮的程序流程“结账”按钮的程序流程如图3-3所示。
图3-3 “结账”按钮的程序流程(2)选房间界面在点击“点菜”按钮后弹出图3-4所示界面。
图3-4 选房间界面“空房间列表框”显示可用的空房间名称,该框有上下滚动条,可以上下拖动以选择房间。
当双击某个空房间时选择该房,程序流程如图3-5所示。
图3-5 选房后的程序流程(3)选菜品界面在双击(即选择)某房间后,弹出图3-6所示界面。
图3-6 选房间界面“菜品列表框”显示菜谱,该框有上下滚动条,可以上下拖动以选择顾客所点的菜品。
当单击“提交”按钮时提交选择的房间和所点的菜品,最后回到初始界面,程序流程如图3-7所示。
图3-7 “提交”按钮的程序流程当单击“取消”按钮时,回到初始界面,程序流程如图3-8所示。
图3-8 “取消”按钮的程序流程(4)结账界面在单击“结账”按钮后,弹出图3-9所示界面。
图3-9 结账界面“在本客户端选房列表框”显示利用本客户端为顾客选房的明细,该框有上下滚动条,可以上下拖动以选择某个房间。
当双击某个房间时,就退掉这个房间。
退房的程序流程如图3-10所示。
图3-10 退房的程序流程3.1.2 服务器端界面设计服务器端界面如图3-11所示。
图3-11 服务器端界面3.2 数据库设计3.2.1 点菜数据库点菜数据库的记录有30个字段:fno、cno。
fno:房间号;cn:菜品的编号。
3.2.2 房间数据库房间数据库的记录有3个字段:fn、fm及fs。
fno:房间号;fname:房间名称;fstatus:房间空闲或占用状态。
3.2.3 菜品数据库点菜数据库的记录有30个字段:cno、cname及cprice。
cno:菜品编号;cname:菜品名称;cprice:菜品价格。
3.3 模块设计3.3.1显示空房间及菜品“显示空房间及菜品”模块的程序流程如图3-12所示。
该模块需要一个参数,当参数为‘f’时,显示空房间列表,否则显示菜品列表。
图3-12 “显示空房间及菜品”模块的程序流程3.3.2显示就餐信息“显示空房间及菜品”模块的程序流程如图3-12所示。
该模块需要一个参数,当参数为‘f’时,显示空房间列表,否则显示菜品列表。
图3-13 “显示就餐信息”模块的程序流程3.3.3客户端收发数据3.3.4服务器端收发数据3.3.5更新房间状态3.3.6查询数据“查询数据”模块的程序流程如图3-16所示。
该模块需要一个参数,“服务器端收发数据”模块调用该模块时,参数为‘k’,“显示房间及其菜品表”模块调用该模块时,参数为指定的房号。
图3-16 “查询数据”模块的程序流程3.3.7显示房间及其菜品表“显示房间及其菜品表”模块的程序流程如图3-17所示。
该模块需要两个参数,分别是“选房房号”、“点菜菜品编号集合”。
图3-17 “显示房间及其菜品表”模块的程序流程难点的解决办法在qt中实现多窗体以及通过以太网收发各类数据是实现本系统的难点。
以下是这两个难点的解决办法。
1 多窗体的切换在qt中采用信号插槽机制来实现多窗体的切换。
假设图7-1所示两个窗体Form1和Form2,Form1中有一个按钮Button1,单击该按钮切换到Form2,在Form2中也有一个按钮Button1,单击该按钮切换到Form1。
图7-1 两个窗体的切换Form1和Form2是两个对等的对象,两者互不为对方的成员,这样在Form1中就不能操作Form2的show()函数,同样,在Form2中也不能操作Form1的show()函数,因此,不能直接通过连接到一个窗体中Button1的Clicked()信号的插槽来显示另一个窗体。
可以考虑让Form1和Form2互发信号以通知对方显示,但qt中信号的发送者和接收者必须是同一个对象的成员或该对象本身,因此要让Form1和Form2互发信号必须要使Form1和Form2成为一个对象的成员。
以下是基于该想法实现的Form1和Form2相互切换代码。
首先在Form1和Form2中定义信号和插槽,form1.h代码如下:#include <qvariant.h>#include <qdialog.h>class QVBoxLayout;class QHBoxLayout;class QPushButton;class Form1 : public QDialog{Q_OBJECTPublic:Form1(QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 );~Form1();QPushButton* PushButton1;signals:viod showform2();//该信号用于连接Form2中的插槽showform()public slots:virtual void showf();//该插槽连接PushButton1的clicked()信号private slots:void showform();//该插槽连接Form2的showform1()信号};Form2.h代码如下:#include <qvariant.h>#include <qdialog.h>class QVBoxLayout;class QHBoxLayout;class QPushButton;class Form2 : public QDialog{Q_OBJECTPublic:Form2(QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 );~Form2();QPushButton* PushButton1;signals:viod showform1();//该信号用于连接Form2中的插槽showform()public slots:virtual void showf();//该插槽连接PushButton1的clicked()信号private slots:void showform();//该插槽连接Form2的showform3()信号};其次,新建FormManager..h,在里面定义一个基于QDialog的类FormManager,用来管理Form1和Form2。
#include <qvariant.h>#include <qdialog.h>class QVBoxLayout;class QHBoxLayout;class Form1;//Form1的前向声明,因为下面要用到Form1,Form2也是如此class Form2;class FormManager : public QDialog{Q_OBJECTPublic:FormManager (QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 );~ FormManager ();Form1 *f1;//Form1和Form2就成了FormManager的成员Form2 *f2;};在FormManager类的实现文件FormManager.cpp中,实现Form1中showform2()信号连接至form2的showform()插槽,Form2中showform1()信号连接至form1的showform()插槽。
代码如下:#include “FormManager..h”#include “form1.h” //窗体Form1的头文件,Form2类似#include “form2.h”#include <qlayout.h>#include <qvariant.h>#include <qtooltip.h>#include <qwhtsthis.h>FormManager.:: FormManager.(QWidget* parent, const char* name, bool modal, WFlags fl ) : QDialog( parent, name, modal, fl ){if ( !name )setName( “FormManager” );resize( 596, 480 );setCaption( tr( “FormManager” );f1 = new Form1(this);f2 = new Form2(this);connect( f1, SIGNAL(showform2()),f2, SLOT(showform() );connect( f2, SIGNAL(showform1()),f1, SLOT(showform() );f1->show();}FormManager.:: ~FormManager.(){}在main()函数中,FormManager对象作为应用程序类对象的主窗体并显示。