餐饮管理系统 - 图文

更新时间:2024-03-14 19:07:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

餐饮管理系统

餐饮管理系统是一个饮食产业不可缺少的部分,它的内容对企业的决策者和管理者都至关重要,所以餐饮管理系统应该能够为用户提供充足的信息和快捷的查询手段。但一直以来人们使用的餐饮管理系统均是以人为主体的,需要很多的人力、物力、财力,且效率不是很高,在系统运营时也可能产生人为的失误,以致餐饮管理工作既繁琐而且不利于分析企业的经营状况。

作为计算机应用的一部分,使用计算机对餐饮信息进行管理,具有人工管理所无法比拟的优点。例如统计结账快速、安全保密性好、可靠性高、存储量大、寿命长、成本低等。这些优点能够极大地提高餐饮管理的效率,增强企业的竞争力,同时也是企业的科学化、正规化管理,与世界接轨的重要条件。通过阅读本章,读者可以学习到:

? 验证不同权限登录用户的方法 ? 使用ListView控件制作桌台显示 ? 使用MenuStrip控件制作系统菜单栏

? 使用ContextMenuStrip控件制作桌台右键菜单 ? 开发餐饮管理系统的具体流程

1 开发背景

近几年来,计算机网络、分布技术日趋成熟,随着科技的发展,餐饮业的竞争也越来越激烈。想在这样竞争激烈的环境下生存,那么就必须运用科学的管理思想与先进的管理方法,使点餐与管理一体化。这样不仅提高了工作效率,也避免了以前手工作业的麻烦,从而使管理者能够准确、有效地管理餐饮。因此,餐饮业的管理者更希望从科学的管理中取得竞争的优势,在竞争激烈的商业市场中取胜。

2 需求分析

随着餐饮业的不断发展,餐饮管理系统的内容对于餐饮业的决策者和管理者来说都非常重要。本系统主要包括桌台显示、消费查询、人事档案及权限等几大部分,本系统具有良好的用户接口,使用方便。具有完善的查询,对维护系统起到辅助决策的作用,能及时、方便、灵活地进行查询、修改、删除等维护性操作。餐饮管理系统有足够的存储容量,满足酒店每日营业的变动,另外,对于操作用户有一定的管理,并对用户的权限有一定的设置。

3 系统设计

3.1 系统目标

本系统属于小型的餐饮管理系统,可以有效地对中小型餐厅消费进行管理。本系统应达到以下目标:

? 系统采用人机交互的方式,界面美观友好,信息查询灵活、方便,数据存储安全可靠。 ? 实现对餐厅顾客开台、点菜/加菜、账目查询和结账等操作。

? ? ? ? 对用户输入的数据进行严格的数据检验,尽可能地避免人为错误。 实现对消费账目自动结算。

实现对消费的历史记录进行查询,支持模糊查询。 系统应最大限度地实现易维护性和易操作性。

3.2 系统功能结构

餐饮管理系统功能结构如图1所示。 餐饮管理系统 基础信息 辅助工具 系统维护 桌 台 信 息 职员信息 日历 计算器 记事本 权限管理 系统备份 系统恢复 口令设置 锁定系统 关于 退出系统 系统设置 帮助 退出 图1 系统功能结构图

3.3 系统预览

餐饮管理系统由多个窗体组成,下面仅列出几个典型窗体,其他窗体参见光盘中的源程序。 主窗体模块运行结果如图2所示,主要功能是链接系统功能菜单、显示所有桌台和显示系统当前状态。点菜模块运行结果如图3所示,主要功能是为顾客点菜。开台模块运行效果如图4所示,主要功能是实现对指定的桌台进行开台操作。结账模块运行效果如图5所示,主要功能是对指定的桌台进行结账操作,同时,清空结账桌台的所有消费信息。

3.4 业务流程图

餐饮管理系统的业务流程图如图6所示。

3.5 程序运行环境

餐饮管理系统在运行中的具体运行环境如下。

? 系统开发平台:Microsoft Visual Studio 2008。 ? 系统开发语言:C#。

? 数据库管理系统:Microsoft SQL Server 2005。

? 运行平台:Windows XP(SP2)/Windows 2000(SP4)/Windows Server 2003(SP1)。 ? 运行环境:Microsoft. NET Framework SDK v2.0。 ? 分辨率:最佳效果1024×768像素。

3.6 数据库设计

在开发餐饮管理系统之前,分析了该系统的数据量。由于系统管理餐饮方面的数据较多,商品信息、消费信息以及账目清单会占用较大的空间,因此选择Microsoft SQL Server 2000数据库存储这些信息,数据库命名为db_MrCy,在数据库中创建了6个数据表用于存储不同的信息,如图7所示。

说明:Microsoft SQL Server 2000数据库的创建过程在第5章已经做过介绍,此处不再赘述。 3.7 数据库概念设计

餐饮管理系统的数据库主要用于存储餐饮管理系统中的数据,由于餐饮管理系统的数据量很大,所以选择了Microsoft SQL Server 2000数据库,数据库中建立一个商品信息表,用于存储所有的商品信息。商品信息实体E-R图如图8所示。

由于商品的种类很多,因此需要对商品进行分类,这样就可以对商品分门别类地进行储存,在查询时可以根据商品类别进行查询。在数据库中建立一个商品类别信息表,用于存储商品的所有类别信息。商品类别信息实体E-R图如图9所示。

当顾客进行消费时,顾客会根据自己的需求消费不同的商品,系统将顾客消费的所有信息存储到数据表中,以便顾客结账时查询,在数据库中建立一个顾客消费信息表用于存储顾客的消费记录。顾客消费信息实体E-R图如图10所示。

餐厅中会有多个桌台供顾客选择,每个桌台会有不同的信息。 例如,大厅-01号桌台被顾客使用,顾客人数为5人等,方便操作员对桌台的操作,在数据库中建立一个桌台信息表用于存储所有桌台的详细信息。桌台信息实体E-R图如图11所示。

为了对系统进行不同的管理,需要为系统建立管理用户。这些用户通过登录模块登录系统,登录成功之后会根据不同的权限对不同的功能模块进行管理,在数据库中建立一个用户信息表,用于存储登录用户信息。用户信息实体E-R图如图12所示。

在餐饮行业中,餐厅服务员起着极其重要的作用,但是由于服务人员数目众多,如果不进行相应的信息记录,可能管理起来会非常困难。因此,需要对服务人员的详细信息进行记录。在数据库中建立一个职员信息表用于存储所有服务人员的信息。职员信息实体E-R图如图13所示。

3.8 数据库逻辑结构设计

根据设计好的E-R图在数据库中创建各表,系统数据库中各表的结构如下。 tb_food(商品信息表)

tb_food用于保存所有商品信息,该表的结构如表1所示。

表1商品信息表

字 段 名 ID foodty foodnum foodname foodprice 数 据 类 型 int char char varchar decimal 长 度 4 10 10 50 9 主 键 是 否 否 否 否 描 述 系统编号 类别编号 商品代号 商品名称 商品价格 tb_foodtype(商品类别信息表)

表tb_foodtype用于保存商品类别信息,该表的结构如表2所

表2 商品类别信息表

字 段 名 ID Foodtype 数 据 类 型 int varchar 长 度 4 50 主 键 是 否 描 述 系统编号 商品类别名称 tb_GuestFood(顾客消费信息表)

表tb_GuestFood用于保存顾客的消费信息,该表结构如表3所示。

表3 顾客消费信息表

字 段 名 ID foodnum foodname 数 据 类 型 int char varchar 4 10 50 长 度 主 键 是 否 否 描 述 系统编号 商品代号 商品名称 foodsum foodallprice waitername beizhu zhuotai datatime char decimal varchar varchar char varchar 10 9 50 50 10 50 否 否 否 否 否 否 消费数量 商品价格 操作员姓名 备注 消费桌台 消费时间 tb_Room(桌台信息表)

表tb_Room用于保存所有桌台信息,该表结构如表4所示。

表4 桌台信息表

字 段 名 ID RoomName RoomJC RoomBJF RoomWZ RoomZT RoomType RoomBZ RoomQT GuestName zhangdanDate Num WaiterName 数 据 类 型 int char char decimal char char char varchar varchar varchar varchar int varchar 长 度 4 10 10 9 10 10 10 50 50 50 50 4 50 主 键 是 否 否 否 否 否 否 否 否 否 否 否 否 描 述 系统编号 桌台名称 桌台简称 桌台包间费 桌台位置 桌台状态 桌台类型 桌台备注 桌台其他信息 顾客姓名 开台时间 顾客人数 操作员姓名 tb_User(用户信息表)

表tb_User用于保存所有系统用户信息,该表结构如表5所示。

表5 用户信息表 字 段 名 ID UserName UserPwd power 数 据 类 型 int varchar varchar char 4 50 50 10 长 度 主 键 是 否 否 否 描 述 系统编号 用户登录名 用户登录密码 用户权限 tb_Waiter(职员信息表)

表tb_Waiter用于保存所有职员信息,该表结构如表6所示。

表6 职员信息表

字 段 名 ID WaiterName CardNum WaiterNum 数 据 类 型 int varchar varchar char 4 50 50 10 长 度 主 键 是 否 否 否 描 述 系统编号 职员姓名 身份证号码 职员编号 Sex Age Tel

char char varchar 10 10 50 否 否 否 性别 年龄 电话 3.9 文件夹组织结构

每个项目都会有相应的文件夹组织结构,如果项目中窗体数量很多,可以将所有的窗体及资源放在不同的文件夹中。如果项目中窗体不是很多,可以将图片、 公共类或者程序资源文件放在相应的文件夹中,而窗体可以直接放在项目根目录下。餐饮管理系统就是按照后者的文件夹组织结构排列的,如图14所示。

4 登录模块设计

4.1 登录模块概述

为了使系统的安全性得到保障,大多数系统都开发登录模块。只有通过登录模块,才能对登录用户进行验证,只有系统的合法用户才可以进入系统的主界面。这也是设计管理系统软件之前必须考虑的问题,整个登录模块的实现过程非常简单,相信读者会很快掌握。登录模块运行结果如图15所示。

4.2 登录模块技术分析

运行本系统的登录模块,用户只需输入用户名和密码,单击“登录”按钮进行验证。登录模块以登录的用户名和密码作为搜索条件,在数据库中进行查询。使用SqlDataReader对象的HasRows属性判断登录用户名和密码是否正确,下面介绍SqlDataReader对象的HasRows属性。

HasRows属性

获取一个值,该值指示SqlDataReader是否包含一行或多行。 语法如下:

public override bool HasRows { get; }

属性值:如果SqlDataReader包含一行或多行,则为true;否则为false。 例如,验证登录用户名和密码是否正确,可以通过以下代码实现: SqlConnection conn = BaseClass.DBConn.CyCon(); conn.Open();

SqlCommand cmd = new SqlCommand(\* from tb_User where UserName='\+ txtName.Text + \SqlDataReader sdr = cmd.ExecuteReader(); sdr.Read();

if (sdr.HasRows) {

MessageBox.Show(\登录成功\\警告\MessageBoxButtons.OK, MessageBoxIcon.Warning); }

登录模块验证的方法有很多,除了本章登录模块的验证方法外,还可以使用第 2章登录模块的验证方法,第2章是通过COUNT聚合函数进行验证的,具体参看第2章登录模块设计中的内容。

4.3 登录模块实现过程

本模块使用的数据表:tb_User 登录模块的具体实现步骤如下:

(1)新建一个Windows窗体,命名为frmLogin.cs,主要用于实现系统的登录功能。该窗体用到的主要控件如表7所示

表7 登录窗体用到的主要控件

字 段 名 控件ID txtName txtPwd btnSubmit btnConcel 主要属性设置 无 PasswordChar属性设置为* Text属性设置为“登录” Text属性设置为“取消” 用 途 输入登录用户名 输入登录用户密码 登录 取消 (2)由于餐饮系统使用Microsoft SQL Server 2000作为后台数据库,因此先要引用命名空间,以便在程序中操作数据库。关键代码如下:

using System.Data.SqlClient

(3)单击“登录”按钮之后,登录模块首先判断是否输入了用户名和密码,如果没有输入用户名和密码将弹出提示框,提示用户输入登录系统的用户名和密码;如果输入了用户名和密码,系统将判断输入的用户名和密码是否正确。关键代码如下:

例程01 代码位置:光盘\\ TM \\06\\ MrCy \\ frmLogin.cs

private void btnSubmit_Click(object sender, EventArgs e) {

if (txtName.Text == \判断用户名是否为空 {

MessageBox.Show(\请输入用户名\\警告\MessageBoxButtons.OK, MessageBoxIcon.Warning); } else {

if (txtPwd.Text == \判断密码是否为空 {

MessageBox.Show(\请输入密码\\警告\MessageBoxButtons.OK, Messan.Warning);

} else {

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库

conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\* from tb_User where UserName='\+ txtName.Text + \

SqlDataReader sdr = cmd.ExecuteReader(); //创建SqlDataReader对象

sdr.Read(); //读取

if (sdr.HasRows) //验证用户名和密码 { sdr.Close();

cmd = new SqlCommand(\txtName.Text + \

SqlDataReader sdr1 = cmd.ExecuteReader(); sdr1.Read();

string UserPower = sdr1[\

conn.Close(); //关闭链接

frmMain main = new frmMain(); main.power = UserPower; main.Names = txtName.Text;

main.Times = DateTime.Now.ToShortDateString(); main.Show(); //打开主窗体

this.Hide(); //隐藏当前登录窗体 } else {

MessageBox.Show(\用户名或密码错误\弹出提示信息 } } }

}

(4)当输入用户名和密码之后,还可以按Enter键登录系统,实现的原理是:在输入密码的文本框的KeyPress事件下,判断是否按了Enter键,如果按了Enter键就会激发“登录”按钮的Click事件。

关键代码如下:

例程02 代码位置:光盘\\ TM \\06\\ MrCy \\ frmLogin.cs

private void txtPwd_KeyPress(object sender, KeyPressEventArgs e) {

if (e.KeyChar == 13) //判断是否按下Enter键 {

btnSubmit_Click(sender, e); //调用“登录”按钮的Click事件 } }

(5)单击“取消”按钮,退出系统登录。关键代码如下: 例程03 代码位置:光盘\\ TM \\06\\ MrCy \\ frmLogin.cs

private void btnConcel_Click(object sender, EventArgs e) {

if (MessageBox.Show(\确定退出系统吗?\\提示\MessageBoxButtons.OKCancel, Messan.Asterisk) == Dialog Result.OK)

{

Application.Exit(); //退出系统 } }

5 主窗体模块设计

5.1 主窗体模块概述

在餐饮系统中主窗体模块是由 3部分组成的。第一部分是位于主窗体模块上端的系统菜

单,主要实现链接系统功能菜单。第二部分是位于主窗体模块中间的桌台显示,主要用于显示餐厅中所有的桌台情况,包括桌台是否已使用、 已使用桌台的客人数量等信息,方便了用户对桌台的管理。 第三部分是位于主窗体模块下端的状态栏,主要用于显示系统当前状态信息。主窗体模块运行结果如图16所示。

双击某个桌台,弹出“桌台基本信息”窗体,用于显示此桌台的详细信息,如图17所示。 在某个桌台上单击鼠标右键,在弹出的快捷菜单中用户可以选择“开台”、“取消开台”、“点/加菜”、“消费查询”和“结账”命令,如图18所示。

5.2 主窗体模块技术分析

开发主窗体模块中的桌台显示时,主要是通过 ListView控件实现的,系统首先从数据库中检索出每个桌台的状态,然后根据不同的状态通过ListView控件的Items属性中的Add方法向控件中添加项目集合,下面进行详细介绍。

(1)Items属性

功能:此属性获取包含控件中所有项的集合。

语法如下:

public ListViewItemCollection Items { get; }

属性值:ListView.ListViewItemCollection包含ListView控件中所有的项。 例如:

private void button9_Click(object sender, EventArgs e) {

SqlConnection con = new SqlConnection(\//链接数据库

con.Open(); //打开数据库

string str = \建立SQL语句 SqlCommand com = new SqlCommand(str, con); //执行SQL语句

SqlDataReader dr = com.ExecuteReader(); //创建SqlDataReader对象 while (dr.Read()) {

ListViewItem lt = new ListViewItem(dr.GetValue(0).ToString()); lt.SubItems.Add(dr.GetValue(1).ToString()); lt.SubItems.Add(dr.GetValue(2).ToString()); this.listView1.Items.Add(lt); //添加项目 }

dr.Close(); con.Close(); }

(2)Add方法

功能:将项添加到具有指定文本和图像的集合。 语法如下:

public virtual ListViewItem Add (string text,int imageIndex) 参数说明:

text:项的文本。

imageIndex:要为该项显示的图像的索引。 返回值:已添加到集合中的 ListViewItem。

例如,在本模块中向控件中添加项集合。关键代码如下: lvDesk.Items.Add(sdr[\

另外,在桌台显示中使用ContextMenuStrip控件实现右键弹出菜单。

ContextMenuStrip控件提供了与某个控件关联的快捷菜单,如图19所示。

其使用方法如下:

(1)双击工具栏中的ContextMenuStrip控件将其添加到Form窗体中。

(2)为ContextMenuStrip控件添加菜单项。

(3)设置控件或窗体的 ContextMenu属性为contextMenuStrip1,运行程序,在窗体或者控件上单击鼠标右键,将出现相应的右键菜单。

5.3 主窗体实现过程

本模块使用的数据表:tb_Room、tb_Waiter、tb_User 主窗体模块的具体实现步骤如下:

(1)新建一个Windows窗体,命名为frmMain.cs,主要用于实现系统的菜单栏、桌台显示和显示系统状态的功能。该窗体用到的主要控件如表8所示。

表8 主窗体中用到的主要控件

字 段 名 控件ID menuStrip1 statusStrip1 imageList1 contextMenuStrip1 lvDesk 主要属性设置 Items属性中添加7个MenuItem项 Items属性中添加8个StatusLabel项 Images属性中添加两个成员 Items属性中添加5个MenuItem项 无 用 途 实现窗体中的菜单 实现系统的状态栏 显示代表桌台状态的图片 实现右键菜单 显示所有桌台 (2)首先创建4个公共变量,方便程序调用。关键代码如下: 例程04 代码位置:光盘\\ TM \\06\\ MrCy \\ frmMain.cs public SqlDataReader sdr; public string power; public string Names; public string Times;

(3)在窗体加载时,首先判断登录用户的权限,根据登录用户的权限分配不同的功能。关键代码如下:

例程05 代码位置:光盘\\ TM \\06\\ MrCy \\ frmMain.cs private void frmMain_Load(object sender, EventArgs e) {

switch (power) {

//权限为0时,说明用户是超级管理员

case \超级管理员\//权限为1时,说明用户是经理

case \经理\

//权限为2时,说明用户是一般用户

case \一般用户\}

toolStripStatusLabel2.Text = Names; //在状态栏中显示登录用户身份 toolStripStatusLabel8.Text = Times; //将登录时间显示在状态栏中 if (power == \{

系统维护ToolStripMenuItem.Enabled = false; //屏蔽“系统维护”功能

openroom.name = names; //将桌台名称赋值给公共变量name openroom.ShowDialog(); //打开“开台单”窗体 } else {

MessageBox.Show(\请选择桌台\弹出提示信息 } }

当在某个桌台上单击鼠标右键时,在弹出的快捷菜单中选择“取消开台”命令,可以取消该桌台的开台状态。关键代码如下:

例程17 代码位置:光盘\\ TM \\06\\ MrCy \\ frmMain.cs

private void 取消开台toolStripMenuItem_Click(object sender, EventArgs e) {

if (lvDesk.SelectedItems.Count != 0) //判断是否有选中项 {

//获取桌台名称

string names = lvDesk.SelectedItems[0].SubItems[0].Text;

SqlConnection conn = BaseClass.DBConn.CyCon(); //打开数据库连接 conn.Open();

SqlCommand cmd = new SqlCommand(\待用',Num=0 where RoomName='\

cmd.ExecuteNonQuery();

cmd = new SqlCommand(\+ \

cmd.ExecuteNonQuery();

conn.Close(); //断开数据库连接 frmMain_Activated(sender, e); } else {

MessageBox.Show(\请选择桌台\弹出提示 } }

当在某个桌台上单击鼠标右键时,在弹出的快捷菜单中选择“点/加菜”命令,可以打开“点/加菜”窗体,为顾客点菜或加菜。关键代码如下:

例程18 代码位置:光盘\\ TM \\06\\ MrCy \\ frmMain.cs

private void 点菜ToolStripMenuItem_Click(object sender, EventArgs e) {

if (lvDesk.SelectedItems.Count != 0) //判断是否有选中项 {

//获取桌台名称

string names = lvDesk.SelectedItems[0].SubItems[0].Text;

frmDC dc = new frmDC();

dc.RName = names; //将桌台名称赋值给公共变量RName

dc.ShowDialog(); } else {

MessageBox.Show(\请选择桌台\弹出提示 }

}

当在某个桌台上单击鼠标右键时,在弹出的快捷菜单中选择“消费查询”命令,可以对指定桌台的消费情况进行查询。关键代码如下:

例程19 代码位置:光盘\\ TM \\06\\ MrCy \\ frmMain.cs

private void 消费查询ToolStripMenuItem_Click(object sender, EventArgs e) {

if (lvDesk.SelectedItems.Count != 0) //判断是否有选中项 {

//获取桌台名称

string names = lvDesk.SelectedItems[0].SubItems[0].Text;

frmSerch serch = new frmSerch();

serch.RName = names; //将桌台名称赋值给公共变量RName serch.ShowDialog(); } else {

MessageBox.Show(\请选择桌台\弹出提示 } }

5.4 单元测试

主窗体模块开发完毕后,进行单元测试。经过对此模块单元测试发现,在用户右键单击桌台以外的空白处,也会弹出右键菜单,如图27所示。

并且选中右键菜单的某个命令后会提示出错,如图28所示。

为了解决这个错误,用到了ListView控件的SelectedItems属性,在餐饮管理系统的右键菜单的代码中首先判断是否存在选中项,如果存在选中项则执行右键菜单中的命令,以右键菜单中的“开台”命令为例,当在空白处单击鼠标右键,在弹出的快捷菜单中选择“开台”命令后,将出现如图 29所示的提示。

程序原始代码如下:

例程20 代码位置:光盘\\ TM \\06\\ MrCy \\ frmMain.cs

private void 开台ToolStripMenuItem_Click(object sender, EventArgs e) {

string names = lvDesk.SelectedItems[0].SubItems[0].Text; //获取桌台名称 frmOpen openroom = new frmOpen();

openroom.name = names; //将桌台名称赋值给公共变量name openroom.ShowDialog(); }

为了屏蔽错误,对原始代码做了如下改进。

例程21 代码位置:光盘\\ TM \\06\\ MrCy \\ frmMain.cs

private void 开台ToolStripMenuItem_Click(object sender, EventArgs e) {

if (lvDesk.SelectedItems.Count != 0) //判断是否有选中项 {

string names = lvDesk.SelectedItems[0].SubItems[0].Text;//获取桌台名称

frmOpen openroom = new frmOpen();

openroom.name = names; //将桌台名称赋值给公共变量name openroom.ShowDialog(); } else {

MessageBox.Show(\请选择桌台\} }

说明:此处只是以右键菜单中的“开台”命令为例,其他命令的改进依此类推。 6 开台模块设计

6.1 开台模块概述

当顾客要进行消费时,首先要看一下是否还有可用的桌台,如果还有空闲的桌台,那么就要为顾客开台,只有在开台之后,才能为顾客点菜、查询和结账。所以开台模块在整个系统中是非常重要的。开台模块用于对指定的桌台进行开台操作,此功能是通过“开台单”窗体实现的,如图30所示。

6.2 开台模块技术分析

在某个桌台上选择其右键菜单中的“开台”命令,将根据该桌台的名称弹出相应的“开台单”窗体,在“开台单”窗体中用户可以对桌台编号、账单日期、顾客名称、用餐人数、 服务员和备注进行录入或更改。数据录入或修改完毕后,单击“保存”按钮完成开台单的操作。在开发此模块时,主要用到了数据库的更新技术,下面进行详细介绍。

UPDATE运算符

功能:更改表中的现有数据。 语法如下:

UPDATE

SET =

[??,=]

[WHERE] 语法中各参数的说明如表9所示。 参 数 table_name view_name SET column_name 描 述 需要更新的数据表名 要更新视图的名称。通过view_name来引用的视图必须是可更新的。用UPDATE语句进行的修改,至多只能影响视图的FROM子句所引用的基表中的一个 指定要更新的列或变量名称的列表 含有要更改数据的列的名称。column_name必须驻留于UPDATE子句中所指定的表或视图中。标识列不能进行更新。如果指定了限定的列名称,限定符必须同UPDATE子句中的表或视图的名称相匹配 expression WHERE 变量、 字面值、 表达式或加上括号返回单个值的subSELECT语句。 expression返回的值将替换column_name中的现有值 指定条件来限定所更新的行 为要更新行指定需满足的条件。 搜索条件也可以是连接所基于的条件。对搜索条件中可以包含的谓词数量没有限制 注意:一定不要忽略WHERE子句,除非想要更新表中的所有行。 例如,将姓名为小吕的年龄修改为28,可以使用下面的代码实现: update tb_ls set age=28 where name='小吕'

6.3 开台模块实现过程

本模块使用的数据表:tb_Room、tb_Waiter 开台模块的具体实现步骤如下:

(1)新建一个Windows窗体,命名为frmOpen.cs,主要用于实现对指定的桌台进行开台操作的功能。该窗体用到的主要控件如表10所示。

(2)首先建立两个公共变量以便程序中调用。关键代码如下: 例程22 代码位置:光盘\\ TM \\06\\ MrCy \\frmOpen.cs public string name;

public SqlConnection conn;

(3)在窗体加载时,将数据库中所有的桌台信息和职员信息检索出来显示在ComboBox控

件上。

关键代码如下:

例程23 代码位置:光盘\\ TM \\06\\ MrCy \\frmOpen.cs

private void frmOpen_Load(object sender, EventArgs e) {

conn = BaseClass.DBConn.CyCon(); //数据库连接 conn.Open(); //打开连接

SqlCommand cmd = new SqlCommand(\ SqlDataReader sdr = cmd.ExecuteReader(); ? while (sdr.Read()) {

cbNum.Items.Add(sdr[\显示所有桌台信息 }

cbNum.SelectedItem= name.Trim(); //设置选中项 sdr.Close();

cmd = new SqlCommand(\ sdr = cmd.ExecuteReader(); ? while (sdr.Read()) {

//显示所有职员信息

cbWaiter.Items.Add(sdr[\

}

cbWaiter.SelectedIndex = 0; //设置选中第一项 sdr.Close(); }? 代码贴士

此处添加所有桌台信息,用于选择顾客消费的桌台。 ? 此处添加所有职员信息,用于选择为顾客开台的职员名称。 ?

(4)在“用餐人数”文本框中输入用餐人数,此数据必须保证为大于0的数字。关键代码如下:

例程24 代码位置:光盘\\ TM \\06\\ MrCy \\frmOpen.cs

private void txtNum_KeyPress(object sender, KeyPressEventArgs e) {

//判断输入的数据是否为数字

if ((e.KeyChar != 8 && !char.IsDigit(e.KeyChar)) && e.KeyChar != 13) {

MessageBox.Show(\请输入数字\ e.Handled = true; } }

(5)当数据输入完毕之后,单击“保存”按钮即可对指定的桌台进行开台操作。关键代码如下:

例程25 代码位置:光盘\\ TM \\06\\ MrCy \\frmOpen.cs

private void btnSave_Click(object sender, EventArgs e)

{

//如果输入的数据为空或者小于等于0时

if (txtNum.Text == \ {

MessageBox.Show(\请输入用餐人数\ } else {

string RoomName = cbNum.SelectedItem.ToString(); //获取开台的桌台名称 SqlCommand cmd1 = new SqlCommand(\tb_Room set GuestName='\+ txtName.Text + \

Date='\+ dateTimePicker1.Value.ToString() + \+ Convert.ToInt32(txtNum.Text) + \

SelectedItem. ToString() + \使用' where RoomName='\+ name + \conn);

cmd1.ExecuteNonQuery(); //更新相应的数据 this.Close(); //关闭窗体 } }

7 点菜模块设计

7.1 点菜模块概述

为顾客选定好桌台,并且开台之后,会根据顾客的需要点菜或购买茶水烟酒之类的消费品,在点菜模块中会显示餐厅特有的一些菜系,用户可以对不同的菜系进行选择。点菜模块运行结果如图 31所示。

7.2 点菜模块技术分析

系统的点菜模块主要利用了 TreeView控件显示所有的菜系,利用 DataGridView控件显示顾客消费的所有信息,当单击某个菜系时,右侧将出现此菜系的所有详细信息,选择菜系后单击“保存”按钮完成对指定桌台的点菜操作。下面对点菜模块中用到的TreeView控件进行介绍。

TreeView控件可以为用户显示节点层次结构,就像在Windows操作系统的资源管理器的左窗格中显示文件和文件夹一样。 树视图中的各个节点都可以包含其他节点。用户可以按展开或折叠的方式显示父节点或包含子节点的节点。另外,通过将树视图的CheckBoxes属性设置为true,可以在节点旁边显示复选框,用户可以通过将节点的Checked属性设置为true或false来选中或清除节点。

TreeView控件的属性及说明如表11所示。

下面详细介绍Nodes属性,该属性用于设置TreeView控件中的所有节点。 语法格式如下:

public TreeNodeCollection Nodes { get; }

属性值:TreeNodeCollection表示分配给树视图控件的树节点。 例如:

private void button1_Click(object sender, EventArgs e) {

treeView1.ImageList = imageList1; //设置TreeView控件的图像源 TreeNode tr = new TreeNode(\公司职员\添加根节点 tr.Nodes.Add(\小张\为根节点添加子节点 tr.Nodes.Add(\小王\为根节点添加子节点 tr.Nodes.Add(\小李\为根节点添加子节点 tr.Nodes.Add(\小刘\为根节点添加子节点 tr.Nodes.Add(\小孰\为根节点添加子节点 tr.Nodes.Add(\小赵\为根节点添加子节点 tr.Nodes.Add(\小懂\为根节点添加子节点 tr.Nodes.Add(\小高\为根节点添加子节点 treeView1.Nodes.Add(tr); //将节点添加到控件中 treeView1.ExpandAll(); //展开控件 }

7.3 点菜模块实现过程

本模块使用的数据表:tb_food、tb_Waiter、tb_Room、tb_GuestFood 点菜模块的具体实现步骤如下:

(1)新建一个Windows窗体,命名为frmDC.cs,主要用于实现系统的点菜功能。该窗体用到的主要控件如表12所示。

(2)首先建立一个公共变量RName,用于接收指定桌台的名称。关键代码如下: 例程26 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs public string RName;

(3)在窗体加载时,程序首先从数据库中检索出所有的菜系名称并显示在TreeView控件上,以便用户选择。关键代码如下:

例程27 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void frmDC_Load(object sender, EventArgs e) {

this.Text = RName + \点/加菜\设置窗体显示问题

TreeNode newnode1 = tvFood.Nodes.Add(\锅底\为控件添加节点 TreeNode newnode2 = tvFood.Nodes.Add(\配菜\ TreeNode newnode3 = tvFood.Nodes.Add(\烟酒\ TreeNode newnode4 = tvFood.Nodes.Add(\主食\

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\conn);

SqlDataReader sdr = cmd.ExecuteReader(); while (sdr.Read())

{

newnode1.Nodes.Add(sdr[3].ToString().Trim()); //为“锅底”添加子节点 }

sdr.Close();

cmd = new SqlCommand(\ sdr = cmd.ExecuteReader(); while (sdr.Read()) {

newnode2.Nodes.Add(sdr[3].ToString().Trim()); //为“配菜”添加子节点 }

sdr.Close();

cmd = new SqlCommand(\ sdr = cmd.ExecuteReader(); while (sdr.Read()) {

newnode3.Nodes.Add(sdr[3].ToString().Trim()); //为“烟酒”添加子节点 }

sdr.Close();

cmd = new SqlCommand(\ sdr = cmd.ExecuteReader(); while (sdr.Read()) {

newnode4.Nodes.Add(sdr[3].ToString().Trim()); //添加子节点 }

sdr.Close();

cmd = new SqlCommand(\ sdr = cmd.ExecuteReader(); while (sdr.Read()) {

//为“主食”添加子节点

cbWaiter.Items.Add(sdr[\

} cbWaiter.SelectedIndex = 0; sdr.Close();

cmd = new SqlCommand(\RoomZT from tb_Room where RoomName='\

string zt = Convert.ToString(cmd.ExecuteScalar()); //获取桌台状态 if (zt.Trim() == \待用\如果处在“待用”状态,则禁用所有操作 {

groupBox1.Enabled = false; groupBox2.Enabled = false; groupBox3.Enabled = false; groupBox4.Enabled = false; }

conn.Close(); //关闭连接 GetData(); //重新绑定数据

tvFood.ExpandAll(); //展开TreeView控件 }

(4)当用户双击某个菜系时,将在右侧显示该菜系的详细信息,以便用户能够准确地选择。关键代码如下:

例程28 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void treeView1_DoubleClick(object sender, EventArgs e) {

string foodname = tvFood.SelectedNode.Text; //获取选择的商品名称

if (foodname == \锅底\|| foodname == \配菜\|| foodname == \烟酒\|| foodname == \主食\

{} //如果选择的文本为以上这几项则不执行任何操作 else {

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开连接

SqlCommand cmd = new SqlCommand(\* from tb_food where foodname='\+ foodname + \

SqlDataReader sdr = cmd.ExecuteReader(); sdr.Read();

txtNum.Text = sdr[\读取商品的编号 txtName.Text = foodname; //显示商品的名称

txtprice.Text = sdr[\读取商品的单价 conn.Close(); //关闭连接

if (txtpnum.Text == \判断消费商品数量是否为空 {

MessageBox.Show(\数量不能为空\

return; } else {

//根据消费商品的数量计算出消费商品的价格

txtallprice.Text = Convert.ToString(Convert.ToInt32(txtprice.Text) * Conve2(txtpnum.Text));

} } }

(5)为了保证消费商品数量文本框中的数据必须为数字,在文本框的KeyPress事件中添加代码控制输入数据的类型。关键代码如下:

例程29 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void txtpnum_KeyPress(object sender, KeyPressEventArgs e) {

//判断是否输入了数字

if ((e.KeyChar != 8 && !char.IsDigit(e.KeyChar)) && e.KeyChar != 13) {

MessageBox.Show(\请输入数字\ e.Handled = true; } }

(6)当用户更改消费商品的数量时,该商品的总价格会随之改变,实现的方法是在 TextBox控件的TextChanged事件中添加代码。关键代码如下:

例程30 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void txtpnum_TextChanged(object sender, EventArgs e) {

if (txtpnum.Text == \判断消费商品数量是否为空 {

MessageBox.Show(\数量不能为空\ return; } else {

if (Convert.ToInt32(txtpnum.Text) < 1) //判断消费商品数量输入是否正确 {

MessageBox.Show(\不能为小于1的数字\ return; } else {

//根据消费商品的数量计算出消费商品的价格

txtallprice.Text = Convert.ToString(Convert.ToInt32(txtprice.Text) * Conve2(txtpnum.Text)); } } }

(7)自定义一个GetData方法,用于显示所有的点菜信息。关键代码如下: 例程31 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void GetData() //自定义的方法用于显示所有点菜信息 {

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 SqlDataAdapter sda = new SqlDataAdapter(\foodnum,foodallprice,waitername,beizhu,zhuotai,datatime from tb_GuestFood where zhuotai='\ DataSet ds = new DataSet(); sda.Fill(ds);

dgvFoods.DataSource = ds.Tables[0]; //对控件进行数据绑定 }

(8)当点菜完毕后,单击“保存”按钮可以对顾客消费的菜系进行保存,以便在结账时

对消费金额进行查询。关键代码如下:

例程32 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void btnSave_Click(object sender, EventArgs e) {

if (txtName.Text == \//判断是否有未填写的项目 {

MessageBox.Show(\请选择菜系\ return; } else {

if (txtpnum.Text == \判断是否填写了消费数量 {

MessageBox.Show(\数量不能为空\ return; } else {

if (Convert.ToInt32(txtpnum.Text) <= 0) //判断消费数量输入是否正确 {

MessageBox.Show(\请输入消费数量\ return; } else {

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开连接 SqlCommand cmd = new SqlCommand(\into tb_Guoodnum,foodname,foodsum,foodallprice, waitername,beizhu,zhuotai,datatime) values('\+ txtNum.Text.Trim() + \+ ext.Trim() + \+ txtpnum.Text.Trim() + \+ Convert.ToDecimal(txtallprice.Text.Trim()) + \+ cbWaiedItem.ToString() + \DateTime.Now.ToString() + \

cmd.ExecuteNonQuery(); conn.Close(); //关闭连接

GetData(); //调用GetData方法显示所有点菜信息

} } } }

(9)如果顾客点菜之后想退掉某个菜,就可以在显示所有消费信息的dataGridView控件中选中欲删除的商品,单击“删除”按钮,即可将菜退掉。关键代码如下:

例程33 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void btnDelete_Click(object sender, EventArgs e) {

if (dgvFoods.SelectedRows.Count > 0) //GetData判断是否选中某条信息 {

string names = dgvFoods.SelectedCells[0].Value.ToString();

//获取欲删除信息的名称

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\from tb_GuestFood where foodname='\

cmd.ExecuteNonQuery();

conn.Close(); //关闭数据库

GetData(); //调用GetData方法显示所有点菜信息 } }

7.4 单元测试

开发完点菜模块后,对此模块进行单元测试以保证其能够正常运行,通过单元测试,开发人员发现,在某些细节上如果不经过处理会出现不可预料的错误。例如,在为某个桌台进行点菜操作时,当用户将数量文本框清空后,将出现错误提示,如图32所示。

程序的原始代码如下:

例程34 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void txtpnum_TextChanged(object sender, EventArgs e) {

if (Convert.ToInt32(txtpnum.Text) < 1) //判断输入的数据是否小于1

{

MessageBox.Show(\不能为小于1的数字\ return; } else {

//根据消费商品的数量计算出消费商品的价格

txtallprice.Text = Convert.ToString(Convert.ToInt32(txtprice.Text) * Conve2(txtpnum.Text)); } }

为了解决这一错误问题,重新对代码进行了更改。更改后的代码如下: 例程35 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void txtpnum_TextChanged(object sender, EventArgs e) {

if (txtpnum.Text == \判断是否输入了消费数量 {

MessageBox.Show(\数量不能为空\ return; } else {

if (Convert.ToInt32(txtpnum.Text) < 1) //判断输入的消费数量是否小于1 {

MessageBox.Show(\不能为小于1的数字\ return; } else {

//根据消费商品的数量计算出消费商品的价格

txtallprice.Text = Convert.ToString(Convert.ToInt32(txtprice.Text) * Conver2(txtpnum.Text));

} } }

在点菜模块中,通过TreeView控件显示所有的食品种类及食品名称。如果不经过处理,当选择食品种类时,由于选择的是食品种类,而不是食品名称,所以在数据库中的商品信息表中查找不到相应的数据,将出现错误提示,如图33所示。

程序的原始代码如下:

例程36 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void treeView1_DoubleClick(object sender, EventArgs e)

{

string foodname = tvFood.SelectedNode.Text; //获取消费商品的名称 SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\foodname + \

SqlDataReader sdr = cmd.ExecuteReader(); sdr.Read();

txtNum.Text = sdr[\获取商品的编号 txtName.Text = foodname; //显示商品名称

txtprice.Text = sdr[\获取商品单价 conn.Close(); //关闭连接

if (txtpnum.Text == \判断是否输入了消费数量 {

MessageBox.Show(\数量不能为空\ return; } else {

//根据消费商品的数量计算出消费商品的价格

txtallprice.Text = Convert.ToString(Convert.ToInt32(txtprice.Text) * Convert.ToInt32(txtpt));

} }

为了屏蔽此错误,对原始代码进行了修改。关键代码如下: 例程37 代码位置:光盘\\ TM \\06\\ MrCy \\frmDC.cs

private void treeView1_DoubleClick(object sender, EventArgs e) {

string foodname = tvFood.SelectedNode.Text; //获取消费商品的名称

if (foodname == \锅底\|| foodname == \配菜\|| foodname == \烟酒\|| foodname == \主食\

{} //如果选择的文本为以上这几项则不执行任何操作 else {

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\* from tb_food where foodname='\

+ foodname + \

SqlDataReader sdr = cmd.ExecuteReader(); sdr.Read();

txtNum.Text = sdr[\获取商品的编号 txtName.Text = foodname; //显示商品名称

txtprice.Text = sdr[\获取商品单价 conn.Close(); //关闭连接

if (txtpnum.Text == \判断是否输入了消费数量 {

MessageBox.Show(\数量不能为空\弹出提示信息 return; } else {

//根据消费商品的数量计算出消费商品的价格

txtallprice.Text = Convert.ToString(Convert.ToInt32(txtprice.Text) * Conve(txtpnum.Text));

} } }

8 结账模块设计

8.1 结账模块概述

顾客消费完毕后,需要对顾客消费清单进行统计,即计算出消费的总额,这些都是通过结账模块实现的。结账模块主要功能是当顾客每次消费时将顾客消费的项目添加到数据库中,在用户结账时通过对数据库的查询,检索出顾客本次消费的商品名称及价格,然后计算出总额,如图34所示。

如果输入的金额小于消费的金额,单击“结账”按钮结账,将弹出“金额不足”的提示信息,如图35所示;如果在“收银”文本框中输入了错误的数据,将弹出如图36所示的提示信息。

8.2 结账模块技术分析

本系统的结账模块,首先从数据库中将顾客消费的所有项目检索出来显示到 DataGridView控件上,以方便管理员校对消费金额,然后通过程序计算后将顾客消费的总额显示出来,当顾客结账时,输入顾客支付的金额,会出现相应的余额,以方便管理员为顾客退还余额。

在开发此模块时,主要用SUM聚合函数以桌台名称为搜索条件,查询出消费的总金额。 SUM聚合函数

功能:返回表达式中所有值的和,或只返回 DISTINCT 值。SUM 只能用于数字列。空值将被忽略。

语法如下:

SUM ( [ ALL | DISTINCT ] expression ) 参数说明:

? ALL:对所有的值进行聚合函数运算。ALL是默认设置。 ? DISTINCT:指定 SUM 返回唯一值的和。

? expression:是常量、 列或函数,或者是算术、 按位与字符串等运算符的任意组合。

expression 是精确数字或近似数字数据类型分类(bit 数据类型除外)的表达式。不允许使用聚合函数和子查询。

返回值:以最精确的 expression 数据类型返回所有表达式值的和。 例如,在聚合和行聚合中使用 SUM。 USE pubs GO

-- Aggregate functions

SELECT type, SUM(price), SUM(advance) FROM titles

WHERE type LIKE '%cook' GROUP BY type ORDER BY type GO

8.3 结账模块实现过程

本模块使用的数据表:tb_GuestFood、tb_Room 结账模块的具体开发步骤如下:

(1)新建一个Windows窗体,命名为frmJZ.cs,主要用于实现对指定的桌台进行结账操作的功能。该窗体用到的主要控件如表13所示。

(2)引用建立两个公共变量,分别用于接收主窗体模块中传递的桌台名称以及根据名称查询消费的总额。关键代码如下:

例程38 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs public string Rname; public string price;

(3)当窗体加载时,首先显示结账的桌台名称,然后通过桌台名称检索出消费的所有账目显示到DataGridView控件上,最后将查询出消费的总金额显示到Label控件上。关键代码如下:

例程39 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs

private void frmJZ_Load(object sender, EventArgs e) {

this.Text = Rname + \结账\设置窗体显示名称 groupBox1.Text = \当前桌台-\

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 SqlDataAdapter sda = new SqlDataAdapter(\foodname,foodsum,foodallprice, waitername,beizhu,zhuotai,datatime from tb_GuestFood where zhuotai='\

DataSet ds = new DataSet(); sda.Fill(ds);

//绑定控件,显示指定桌台的所有消费信息 dgvRecord.DataSource = ds.Tables[0]; conn.Open(); //打开连接

SqlCommand cmd = new SqlCommand(\sum(foodallprice) from tb_GuestFood where zhuotai='\

price = Convert.ToString(cmd.ExecuteScalar()); //得到顾客消费的总金额 if (price == \判断消费总金额为空时 {

lblprice.Text = \使总金额显示为0 btnJZ.Enabled = false; }

Else {

cmd = new SqlCommand(\RoomBJF from tb_Room where RoomName='\

bjf = cmd.ExecuteScalar().ToString();

if (bjf == \ {

btnJZ.Enabled = true; lblprice.Text = price + \+ (Convert.ToDecimal(Convert.ToDouble(price) * Convert.ToDouble(0.95))).ToString(\

}

else {

btnJZ.Enabled = true;

lblprice.Text = price + \

(Convert.ToDecimal(Convert.ToDouble(price) * Convert.ToDouble(0.95)) + Convert.ToDecimal(bjf)).ToString(\

}

conn.Close(); //关闭连接 } }

(4)在输入顾客支付金额文本框的KeyPress事件下添加代码,判断文本框中是否输入了正确的数据。关键代码如下:

例程40 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs

private void txtmoney_KeyPress(object sender, KeyPressEventArgs e) {

//判断是否输入了数字

if ((e.KeyChar != 8 && !char.IsDigit(e.KeyChar)) && e.KeyChar != 13) {

MessageBox.Show(\请输入数字\ e.Handled = true; } }

(5)当管理员在“收银”文本框中输入顾客支付的金额后,系统将自动计算出退还顾客的金额。

关键代码如下:

例程41 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs

private void txtmoney_TextChanged(object sender, EventArgs e) {

if (price == \首先判断金额是否为空 {

lbl0.Text = \金额为空时,使金额显示为0 } else {

if (txtmoney.Text == \判断输入了顾客支付的金额 {

txtmoney.Text = \如果没有输入则自动变成0

lbl0.Text = \ } else {

//计算出应该支付给顾客的余额 lbl0.Text =

Convert.ToDecimal(Convert.ToDouble(txtmoney.Text.Trim())-Convert.ToDouble(price) * Convert.ToDouble(0.95) - Convert.ToDouble(bjf)).ToString(\

} } }

(6)当顾客支付了消费金额后,单击“结账”按钮完成对顾客消费的结账操作,同时将顾客所在的桌台状态设置为“待用”。关键代码如下:

例程42 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs

private void btnJZ_Click(object sender, EventArgs e) {

if (txtmoney.Text == \首先判断是否输入了支付金额 {

MessageBox.Show(\请先结账\ return; } else {

if (lbl0.Text.Substring(1, 1) == \判断支付的金额是否大于消费金额 {

MessageBox.Show(\金额不足\ return; } else {

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\from tb_GuestFood where zhuotai='\

cmd.ExecuteNonQuery();

cmd = new SqlCommand(\tb_Room set RoomZT='待用',Num=0,WaiterName='' where RoomName

='\

cmd.ExecuteNonQuery();

conn.Close(); //断开连接 this.Close(); //关闭窗口 } }

}

9 开发技巧与难点分析

在开发餐饮管理系统时,总结了一些开发技巧与难点。现在对这些技巧和难点进行分析,希望能与读者朋友一起分享,作者总结出以下几点。

(1)登录模块中的技巧与难点

在开发本模块的过程中使用的技巧是:当输入用户名和密码之后,可以直接按 Enter键进行登录,而不必单击“登录”按钮。实现这一功能的代码如下:

例程43 代码位置:光盘\\ TM \\06\\ MrCy \\frmLogin.cs

private void txtPwd_KeyPress(object sender, KeyPressEventArgs e) {

if (e.KeyChar == 13) //判断是否按了Enter键 {

btnSubmit_Click(sender, e); //激发按钮的Click事件 } }

在开发此模块中遇到的难点即是利用哪种方式验证用户名和密码的正确性,经过慎重的考虑,决定采用与用户信息表中的用户名和密码作比对,通过返回值判断是否为合法的用户。代码如下:

例程44 代码位置:光盘\\ TM \\06\\ MrCy \\frmLogin.cs

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\count(*) from tb_User where UserName='\+ txtName.Text + \

UserPwd='\

int i = Convert.ToInt32(cmd.ExecuteScalar()); //返回值 (2)主窗体模块中的技巧与难点

在开发主窗体模块时,首先考虑如何才能将所有的桌台都显示出来以及使用什么控件进行显示,通过对所有控件的特点进行分析,决定采用 ListView控件显示所有桌台。因为此控件可以自定义集合中各项的图标,并且可以循环添加集合中的项。关键代码如下:

例程45 代码位置:光盘\\ TM \\06\\ MrCy \\frmMain.cs

private void frmMain_Activated(object sender, EventArgs e) {

lvDesk.Items.Clear(); //清空控件的集合

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 conn.Open(); //打开数据库

SqlCommand cmd = new SqlCommand(\ sdr = cmd.ExecuteReader(); while (sdr.Read()) {

string zt = sdr[\获取桌台状态 AddItems(zt); //添加各项

}

conn.Close(); //关闭连接 }

在开发中遇到的难点是:如果在实际应用中突然断电或者计算机重新启动,当再次进入系统时,如何让历史记录不变,让桌台图标能够正确显示当前桌台的准确信息,经过设计,决定在数据库中针对每个桌台建立一个字段,用于标识此桌台的当前状态,每次重新进入系统,都会从数据库中检索出每个桌台的状态,然后根据状态为每个桌台添加不同的图标。关键代码如下:

例程46 代码位置:光盘\\ TM \\06\\ MrCy \\frmMain.cs private void AddItems(string rzt) {

if (rzt == \使用\如果状态是“使用”则添加索引为1的图片 {

lvDesk.Items.Add(sdr[\ }

else //否则添加索引为0的图片 {

lvDesk.Items.Add(sdr[\ } }

(3)结账模块中的技巧与难点

在开发结账模块时,通过一些小技巧,能够很好地实现用户想得到的结果。例如,顾客消费完毕准备付账时,当操作员输入顾客支付的金额后,系统会自动地显示出应该为顾客找还的金额,这个金额的表现形式有一定的限制,如图37所示。

实现起来并不复杂,计算出金额数量后,将其转换成字符串形式。实现代码如下: 例程47 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs

private void txtmoney_TextChanged(object sender, EventArgs e) {

if (price == \首先判断金额是否为空 {

lbl0.Text = \金额为空时,使金额显示为0 } else {

if (txtmoney.Text == \判断输入了顾客支付的金额 {

txtmoney.Text = \如果没有输入则自动变成0 lbl0.Text = \ } else {

//计算出应该支付给顾客的余额

lbl0.Text =

Convert.ToDecimal(Convert.ToDouble(txtmoney.Text.Trim()) - Convert.ToDouble(price) * Convert.ToDouble(0.95) - Convert.ToDouble(bjf)).ToString(\

} } }

作者总结出转换成字符串格式的几点方法如表14所示。

此处开发的难点在于一些细节上的分析,输入顾客支付金额的文本框中的数据必须保证为数字,否则会出现错误,因此作者在控件的KeyPress事件下加入了以下代码:

例程48 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs

private void txtmoney_KeyPress(object sender, KeyPressEventArgs e) {

if ((e.KeyChar != 8 && !char.IsDigit(e.KeyChar)) && e.KeyChar != 13) {

MessageBox.Show(\请输入数字\ e.Handled = true; } }

而在计算顾客消费总额时,是通过读取数据库中顾客消费的所有费用的总和,然后对总和进行打折优惠,最后得到的结果就是顾客应该支付的金额。关键代码如下:

例程49 代码位置:光盘\\ TM \\06\\ MrCy \\frmJZ.cs public string Rname; public string price;

private void frmJZ_Load(object sender, EventArgs e) {

this.Text = Rname + \结账\设置窗体显示名称 groupBox1.Text = \当前桌台-\

SqlConnection conn = BaseClass.DBConn.CyCon(); //连接数据库 SqlDataAdapter sda = new SqlDataAdapter(\

foodnum,foodallprice,waitername,beizhu,zhuotai,datatime from

tb_GuestFood where zhuotai='\ DataSet ds = new DataSet(); sda.Fill(ds);

dgvRecord.DataSource = ds.Tables[0]; //绑定控件,显示指定桌台的所有消费信息

conn.Open(); //打开连接

SqlCommand cmd = new SqlCommand(\sum(foodallprice) from tb_GuestFood where zhuotai='\

price = Convert.ToString(cmd.ExecuteScalar()); //得到顾客消费的总金额 if (price == \判断消费总金额为空时 {

lblprice.Text = \使总金额显示为0 btnJZ.Enabled = false; } else {

cmd = new SqlCommand(\RoomBJF from tb_Room where RoomName='\

bjf = cmd.ExecuteScalar().ToString(); if (bjf == \ {

btnJZ.Enabled = true; lblprice.Text = price + \+ (Convert.ToDecimal(Convert.ToDouble(price) * Convert.

ToDouble (0.95))).ToString(\ } else {

btnJZ.Enabled = true; lblprice.Text = price + \+ (Convert.ToDecimal(Convert.ToDouble(price) *

Convert. ToDouble(0.95)) + Convert.ToDecimal(bjf)).ToString(\ }

conn.Close(); }

10 ListView控件应用

1.功能

ListView控件可以显示带图标的项列表,用户可使用该控件创建类似 Windows资源管理器那样的用户界面。ListView控件如图38所示。

2.属性

ListView控件常用属性及说明如表15所示。

表15 ListView控件常用属性及说明

下面对比较重要的属性进行详细介绍。 (1)View属性

用于获取或设置项在控件中的显示方式。 语法如下:

public View View { get; set; }

属性值:View值之一,默认为LargeIcon。 View的属性值及说明如表16所示。

表16 View的属性值及说明

(2)FullrowSelect属性

用于指定是只选择某一项,还是选择某一项所在的整行。 语法如下:

public bool FullRowSelect { get; set; }

属性值:如果单击某项会选择该项及其所有子项,则为 true;如果单击某项仅选择项本身,则为false。默认为false。

说明:除非将ListView控件的View属性设置为Details,否则FullRowSelect属性无效。当ListView显示带有许多子项的项时,通常使用FullRowSelect属性,并且,在由于控件内容的水平滚动而无法看到项文本时,能够查看选定项是非常重要的。

(3)GridLines属性

指定在包含控件中项及其子项的行和列之间是否显示网格线。 语法如下:

public bool GridLines { get; set; } 属性值:如果在项及其子项的周围绘制网格线的,则为true;否则为false。默认为false。 说明:除非将ListView控件的View属性设置为Details,否则GridLines属性无效。 例如,ListView控件可以以表格的形式显示数据,将ListView的View属性设置为Details,然后通过 Columns 属性向 ListView 中添加列,ListView 控件便呈现出表格的形状。当单击表格时,ListView控件默认为单击第一项,当单击表格时,将整行数据选中。运行结果如图39所示。

程序实现代码如下:

private void button1_Click(object sender, EventArgs e) {

listView1.FullRowSelect = true; }

(4)Items属性

此属性获取包含控件中所有项的集合。 语法如下:

public ListViewItemCollection Items { get; }

属性值:ListView.ListViewItemCollection包含ListView控件中所有的项。 (5)SelectedItems属性

此属性获取在控件中选定的项。 语法如下:

public SelectedListViewItemCollection SelectedItems { get; }

属性值:ListView.SelectedListViewItemCollection包含在控件中选定的项。如果当前

没有选定的项则返回空ListView.SelectedListViewItemCollection。

例如,利用ListView控件制作导航界面。运行程序,在左边的ListView控件中选择员工姓名,在右边即可显示出对应员工的详细信息。运行结果如图40所示。

40 ListView

程序主要代码如下:

public void getScoure(string str_name) {

//连接数据库 SqlConnection con = new SqlConnection(\

con.Open();

SqlCommand com = new SqlCommand(\人员姓名= '\str_name + \

SqlDataReader dr = com.ExecuteReader(); while (dr.Read()) {

txtId.Text = dr[0].ToString(); //获取员工编号 txtName.Text = dr[1].ToString(); //获取员工姓名 txtEmpty.Text = dr[2].ToString(); //获取员工部门 txtSex.Text = dr[3].ToString(); //获取员工性别 txtAge.Text = dr[4].ToString(); //获取员工年龄 txtXueLi.Text = dr[5].ToString(); //获取员工学历 txtTeching.Text = dr[6].ToString(); //获取员工职称 }

dr.Close();

con.Close(); //关闭连接 }

public string str_name; //变量,当前选择的值

private void listViewEmpty_Click(object sender, EventArgs e) {

str_name = listViewEmpty.SelectedItems[0].SubItems[0].Text; //当前选择的值 if (str_name != null) {

getScoure(str_name);

} }

(6)BackgroundImage属性

此属性获取或设置在控件中显示的背景图像。 语法如下:

public virtual Image BackgroundImage { get; set; } 属性值:Image表示在控件的背景中显示的图像。 (7)BackgroundImageTiled属性

此属性获取或设置一个值,该值指示是否应平铺ListView的背景图像。 语法如下:

public bool BackgroundImageTiled { get; set; }

属性值:如果平铺ListView的背景图像,则为true;否则为false。默认为false。 使用ListView控件时,默认其背景颜色为白色,如果在其中显示图标,背景会显得有些不和谐,这时,如果把ListView控件的背景设置为一个底纹图片,界面就会变得协调统一。通过使用代码可以实现在ListView控件中绘制底纹的功能。运行结果如图41所示。

程序实现代码如下:

private void Form1_Load(object sender, EventArgs e) {

listView1.BackgroundImage = imageList1.Images[1]; //设置背景图片

listView1.BackgroundImageTiled = true; }

3.方法

ListView控件常用方法及说明如表17所示。 表17 ListView控件常用方法及说明

下面对比较重要的方法进行详细介绍。 (1)HitTest方法

该方法是指在给定x和y坐标的情况下,提供项信息。 语法如下:

public ListViewHitTestInfo HitTest (int x,int y) 参数说明:

? x:要在该处检索项信息的x坐标。 ? y:要在该处检索项信息的y坐标。 (2)Clear方法

该方法用于删除ListView控件中所有的项。 语法如下:

public void Clear ()

例如,下面的代码用来删除名称为lvStudent的ListView控件的所有项。 lvStudent.Items.Clear(); 4.事件

ListView控件常用事件及说明如表18所示。

表18 ListView控件常用事件及说明

下面对比较重要的事件进行详细介绍。 (1)ItemCheck事件

该事件在选中ListView控件项时触发。 语法如下:

public event ItemCheckEventHandler ItemCheck (2)Click事件

该事件在单击ListView控件列时触发。 语法如下:

public event EventHandler Click

例如,单击ListView控件的某行,将姓名显示在文本框中。运行结果如图42所示。

本文来源:https://www.bwwdw.com/article/q3e8.html

Top