*******上个学期学习JAVA课程(虽然上学期为ACM集训没有去上课),这学期就是JAVA
程序设计实战,才开始学习JAVA。JAVA课程实战,老师给出点菜系统的界面和功能说明
文档,让我们编程实现实现这个小系统,挺简单的小系统,也是自己第一次写JAVA应用程序。
项目下载地址:http://pan.baidu.com/s/1bp6Oh7T
提取密码:2afe
*******该系统实现使用的是:JDK版本 1.8;数据库类型与版本:Mysql 5.5.27 ;
MySql驱动版本:5.1.44系统中所有文件(包括数据库以及数据库中表的设计)均采用utf8
编码。(主要就是防止中文写不进去数据库,或写入数据库乱码问题)。
*******Mysql数据库中的编码设置如下:
如果遇到编码问题而导致数据库写入中文乱码,可以直接去my.ini文件中修改编码类型。
用SQL语句建立数据库时使用utf8编码,建立表的时候也使用utf8编码。
*******面向用户的点菜系统有三个界面:
1.用户操作主界面 (MainFrame)
2.菜品选择界面(chooseDishes)
3.显示用户消费明细界面(showOrderDetail)
*******该系统有五个类:MainFrame类(main方法所在类),chooseDishes类,选菜类,
showOrderDetail,消费信息显示类,DataOperator(自写数据库操作类),
MyCanvas(自己继承Canvas类,重写的画布类)
*******三个界面图示如下:
1.用户操作主界面:
*******界面与功能说明:
*******用户操作主界面布局:将界面划分为三块,分别是上部面板(upPanel),中部面板(middlePanel),
和下部面板(bottomPanel),窗体使用默认布局,上部面板和下部面板使用FlowLayout布局,
并适当设定控件间距,以达到界面美观。中部面板使用box进行布局。
*******用户操作主界面功能说明:
*******1.1 : 只有在有桌号的情况下,方可进行点菜,因此未输入桌号前,四个点菜按钮和显示
消费明细,结束点菜按钮均未不可用,当输入桌号后,获取当前系统时间并显示,并且用于
输入桌号的文本框和显示系统时间的文本框设置为不可编辑状态(用户点菜结束前,桌号不
允许发生改变),同时4个点菜按钮和消费明细,结束点菜按钮均变为可用状态。
*******1.2 :当选择四个点菜按钮的时候,调用选菜类(chooseDishes),进行相应菜品的选择
*******1.3 :点击显示消费明细按钮的时候,将该桌客人的选菜目录,和消费明细显示给顾客,
供其浏览。
*******1.4:当选择结束点菜的时候 ,代表该桌客户已确认下单,恢复输入桌号的文本框,和
和显示系统时间的文本框为可编辑状态。
*******1.5 :当选择结账按钮的时候,输入相应的桌号,客人用餐离开时进行结账,则清除该
桌客人在数据库中的点菜记录,并将该记录写入文本文档,为商家做一订单记录保留。
*******注意:已下单的桌子是已经有客人的桌子,在此我使用hashSet,集合这种数据结构
可以保证内部元素只能出现一次,所以对于已下单的桌子,其有客人了,如果不小心输入
错了桌号,则我们可用通过检测输入的桌号是否在集合中来确定该桌能够点菜。在结账
的时候我们均需要检测输入的要结账的桌号是否有客人,只有在该桌有客人的时候才能
进行结账,结账之后将该桌子编号从集合删除。该系统默认饭店有15桌,所以桌号数据
输入必须在1~15之内,否则将进行桌号错误提醒。
2.菜品选择界面:
菜品选择界面功能描述:
*******2.1:左侧列表呈现饭店提供的菜品,右侧列表是用户选择的菜品。当点中左侧菜品
时,该菜品的名称显示在上方文本框,可以通过+,-按钮,进行该菜品份数的增加和减少
操作,并且设定菜品份数文本框最小值为1,不可低于最小值,并且点中左侧列表菜品,
将该菜品的信息绘制在下方画布供用户参考。
*******2.2 :选中左侧菜品后,点击添加菜品按钮,若右侧列表框无该菜品,则进行添加操作。
*******2.3 : 选中右侧菜品后,点击移除菜品按钮,则移除该菜品
*******2.4 : 点击随机推荐时,为用户随机推荐三种未选菜品,若饭店未点菜品不足三种,则
推荐剩余所有菜品
*******2.5 : 当点击结束点菜按钮时,返回点菜系统主界面,用户可以继续选择点其他类别的
菜品。
*******注意:增加菜品和移除菜品时,必须先选中菜品,否则提示用户先选中菜品,其次添加
菜品必须时用户未的选择菜品。
3.显示用户消费明细界面:
显示点菜详情界面功能描述:
*******该界面无额外功能,只提供显示消费账目的功能。
*******结账后,将桌子对应的表的信息写入文本文档,生成一条消费记录,将数据库中
对应的信息清楚。如现在结10号桌的帐,在文本文档中留下记录。
数据库设计:
顺便说一下指令:
mysql -u root -p 回车输入密码,进入mysql
show databases 查看数据库
use 数据库名 进入数据库
show tables 查看数据库中的表
quit退出
然后可以写sql语句进行各种操作。
*******系统供分了四类菜品:荤菜,素菜,主食,汤粥四类。其在数据库中表的设计
*******如下图所示:(我的数据库名为dishInfo,下图显示荤菜表的设计,其他三个表与此相同)
*******对应于每一桌用户,都建立一个表,名字是table+桌子编号,用来存在该桌客人的点菜信息。如下图所示
*******表内部的设计如下图所示:
*******这些表中均以Did为主键,虽然菜品名称都各不相同,但是我采取给菜品弄了编号,因为网上下载
的菜品图片是用菜品编号一个个命名的。
代码:
MainFrame.java(MainFrame类,系统主界面)
package orderDishes;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
/**
* @description 该类时点餐系统的主类
* @author 温雅新
* @date 2017/10/13
*/
public class MainFrame extends JFrame implements ActionListener {
private JLabel tableIndex; //静态文本用来显示“请输入桌号:”这条文本
private JTextField tableIndexText; //用来接收桌号的文本框
private JLabel date; //用来显示“点菜日期”的静态文本
private JTextField dateText; //用来显示日子的文本框
private HashSet<String> idSet = new HashSet<String>();
private String[] timeArray = new String[20];
//集合里面的元素唯一,当某桌有客人的时候,不能输入该桌号点餐,用来防止输入出错
private JButton meatDishes; //荤菜按钮
private JButton vegetableDishes; //素菜按钮
private JButton stapleDishes; //主食按钮
private JButton soupDishes; //汤粥按钮
private JButton showDetail; //显示订单详情按钮
private JButton stopOrder; //结束点菜按钮
private JButton payMoney; //付款按钮
/**
* @description MainFram类的构造函数,完成该类对象的初始化工作
* @param 无参数
* @return 无返回值
*/
public MainFrame() {
this.setTitle("欢迎点菜"); //设置窗体标题
this.setVisible(true); //设置窗体可见,窗体该属性默认不可见,果果忘记,窗体存在但是看不到
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置点击关闭按钮关闭
tableIndex = new JLabel("请输入您的桌号:"); //实例话静态文本
tableIndexText = new JTextField(15); //实例化文本框
date = new JLabel("点餐日期与时间:"); //实例化静态文本
dateText = new JTextField(20); //实例化文本框
//为接收桌号的文本框设置事件监听器以便在输入回车的时候触发事件
tableIndexText.addActionListener(this);
/*该界面设计窗体使用默认布局,将界面分为上中下三个部分,分别由
* upPanel,middlePanel,bottomPanel构成。
* 三个面板使用流动布局,(当然使用其他布局方式也可以)
* 但是我根据系统界面特征,选择流动布局设计简单
* */
JPanel upPanel = new JPanel();
FlowLayout fl = new FlowLayout(FlowLayout.CENTER,20,50);
upPanel.setLayout(fl); //设置面板布局方式为流动布局
//将第一模块的控件添加到这个面板上来
upPanel.add(tableIndex);
upPanel.add(tableIndexText);
upPanel.add(date);
upPanel.add(dateText);
this.add(BorderLayout.NORTH,upPanel);
//将该面板添加到窗体北部(也就是上方)
//实例化四个按钮
meatDishes = new JButton("荤菜");
vegetableDishes = new JButton("素菜");
stapleDishes = new JButton("主食");
soupDishes = new JButton("汤粥");
//只有在输入桌号的前提下,四个按钮才可用,所以初始化为按钮不可用
meatDishes.setEnabled(false);
vegetableDishes.setEnabled(false);
stapleDishes.setEnabled(false);
soupDishes.setEnabled(false);
//为四个按钮添加事件监听器
meatDishes.addActionListener(this);
vegetableDishes.addActionListener(this);
stapleDishes.addActionListener(this);
soupDishes.addActionListener(this);
//中部面板,采用的布局方式是用box实现
JPanel middlePanel = new JPanel();
//为该面板添加带标题的边框,一边用户知道这些按钮的作用
middlePanel.setBorder(BorderFactory.createTitledBorder("菜品分类"));
//基础box,是水平的,用于容纳两个竖直的box
Box baseBox = Box.createHorizontalBox();
//一个竖直的box
Box box1 = Box.createVerticalBox();
box1.add(Box.createVerticalStrut(50)); //添加间距
box1.add(meatDishes); //添加按钮
box1.add(Box.createVerticalStrut(100)); //添加间距
box1.add(stapleDishes); //添加按钮
Box box2 = Box.createVerticalBox(); //一个竖直的box
box2.add(Box.createVerticalStrut(50));
box2.add(vegetableDishes);
box2.add(Box.createVerticalStrut(100));
box2.add(soupDishes);
//把两个竖向的box添加到横向的baseBox里面
baseBox.add(box1);
baseBox.add(Box.createHorizontalStrut(150));
baseBox.add(box2);
middlePanel.add(baseBox);
this.add(middlePanel);
//BorderLayout布局不指定方向,默认添加到中部
//实例化三个按钮
showDetail = new JButton("显示点菜明细");
stopOrder = new JButton("结束本次点菜");
payMoney = new JButton("结账");
//只有在输入桌号的前提下,这两个按钮才可用,初始设置为不可用
showDetail.setEnabled(false);
stopOrder.setEnabled(false);
//为三个按钮添加事件监听器
showDetail.addActionListener(this);
stopOrder.addActionListener(this);
payMoney.addActionListener(this);
JPanel bottomPanel = new JPanel();
FlowLayout f2 = new FlowLayout(FlowLayout.CENTER,100,50);
bottomPanel.setLayout(f2);
bottomPanel.add(showDetail);
bottomPanel.add(stopOrder);
bottomPanel.add(payMoney);
this.add(BorderLayout.SOUTH,bottomPanel);
this.setBounds(500,100,800,600); //设置窗体大小
this.setResizable(false); //设置窗体大小不可变
}
//@Override
/**@description 该函数用于响应各个控件触发的事件
* @param 事件
* @return 无
*/
public void actionPerformed(ActionEvent event) {
// TODO Auto-generated method stub
/**
* 我设计的系统,默认饭店有15桌,所以输入桌号后,先
* 转化成整数,然后判断做好是否合法,如果合法,通过
* 集合判断该桌子是否已有客人,如果有客人,则提示
* 用户选择其他桌,否则将该桌号插入集合,让用户进行
* 点菜。
*/
if(event.getSource() == tableIndexText) {
String id = tableIndexText.getText();
//如果桌号在集合中,该桌已有客人
if(!idSet.add(id)) {
JOptionPane.showMessageDialog(this,"该桌已有客人,请选择其他桌号.");
}else {
int num = Integer.parseInt(id);
//判断桌号输入是否合法
if(num<0 && num>15) {
JOptionPane.showMessageDialog(this, "桌号输入错误,请重新输入");
}else {
//放入集合
idSet.add(id);
//获取当前事件并显示
Date nowTime = new Date();
SimpleDateFormat matter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = matter.format(nowTime);
this.dateText.setText(date);
int index = Integer.parseInt(id);
timeArray[index] = dateText.getText();
//设置这些控件不可用,直到用户下单恢复其可用
tableIndexText.setEditable(false);
dateText.setEditable(false);
//点菜按钮恢复成可用状态
meatDishes.setEnabled(true);
vegetableDishes.setEnabled(true);
stapleDishes.setEnabled(true);
soupDishes.setEnabled(true);
showDetail.setEnabled(true);
stopOrder.setEnabled(true);
}
}
}
/**
* 如果事件源是荤菜按钮,则说明用户要点荤菜,调用选菜类,通过选菜类的
* 构造函数把桌号和菜品所属类型信息一并传入。
*/
if(event.getSource() == meatDishes) {
try {
int num = Integer.parseInt(tableIndexText.getText());
chooseDishes cd = new chooseDishes(num,"meatdishestable");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 如果事件源是素菜按钮,则说明用户要点素菜,调用选菜类,通过选菜类的
* 构造函数把桌号和菜品所属类型信息一并传入。
*/
if(event.getSource() == vegetableDishes) {
try {
int num = Integer.parseInt(tableIndexText.getText());
chooseDishes cd = new chooseDishes(num,"vegetableDishesTable");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 如果事件源是主食按钮,则说明用户要点主食,调用选菜类,生成选菜类的实例时
* 通过构造函数把桌号和菜品所属类型信息一并传入
*/
if(event.getSource() == stapleDishes) {
try {
int num = Integer.parseInt(tableIndexText.getText());
chooseDishes cd = new chooseDishes(num,"stapleDishesTable");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 如果事件源是汤粥按钮,则说明用户要点汤粥,调用选菜类,生成选菜类的实例时通过
* 其构造函数把桌号和菜品所属类型信息一并传入。
*/
if(event.getSource() == soupDishes) {
try {
int num = Integer.parseInt(tableIndexText.getText());
chooseDishes cd = new chooseDishes(num,"soupDishesTable");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 如果事件源是显示点菜明细,生成showOrderDetail类,将该桌用户
* 所点菜的信息弹出供用户阅览。
*/
if(event.getSource() == showDetail) {
int num = Integer.parseInt(tableIndexText.getText());
try {
showOrderDetail show = new showOrderDetail(num);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 如果事件源是结束点菜(stopOrder),则恢复其他按钮可用即可,可以
* 让其他桌的客人点菜
*/
if(event.getSource() == stopOrder) {
tableIndexText.setText("");
dateText.setText("");
tableIndexText.setEditable(true);
dateText.setEditable(true);
meatDishes.setEnabled(false);
vegetableDishes.setEnabled(false);
stapleDishes.setEnabled(false);
soupDishes.setEnabled(false);
showDetail.setEnabled(false);
stopOrder.setEnabled(false);
}
/**
* 如果事件源是付款(payMoney),弹出询问框输入要结账的桌号
* 如果该桌号在集合中存在,则可以结账,否则输入出错,同样
* 显示账单详情,让用户浏览,然后清空数据库中该桌号对应点菜表
* 的信息,并将该信息备份到文本文档中,生成一条记录,留给商家
* 备份。
*/
if(event.getSource() == payMoney) { ///结账
String tableId = JOptionPane.showInputDialog(null,"输入要结算的桌号:\n");
int number = Integer.parseInt(tableId);
String _number = String.valueOf(number);
if(!idSet.add(_number)) {
try {
showOrderDetail show = new showOrderDetail(Integer.parseInt(tableId));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//记录数据后并清除。
String fileName = "myFile\\record.txt";
try {
RandomAccessFile file = new RandomAccessFile(fileName,"rw");
long fileLength = file.length(); ///把文件指针移动到文件尾部
file.seek(fileLength);
String str;
str = "桌号:" + _number + " 日期:" + timeArray[number] + "\n";
file.write(str.getBytes("utf-8"));
DataOperator DO = new DataOperator();
String sql = "select * from table" + _number;
ResultSet rs = DO.getResult(sql);
int sum = 0;
while(rs.next()) {
str = rs.getString(1) + "\t";
file.write(str.getBytes("utf-8"));
str = rs.getString(2) + "\t";
file.write(str.getBytes("utf-8"));
str = rs.getString(3) + "\t";
file.write(str.getBytes("utf-8"));
String temp = rs.getString(4);
sum = sum + Integer.parseInt(temp);
str = rs.getString(4) + "\t";
file.write(str.getBytes("utf-8"));
str = rs.getString(5) + "\n";
file.write(str.getBytes("utf-8"));
}
str = "费用合计: " + String.valueOf(sum) + "\n";
file.close();
idSet.remove(tableIndexText.getText()); ///从集合中删除桌号。
sql = "delete from table" + tableIndexText.getText();
DO.deleteRecord(sql);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
JOptionPane.showMessageDialog(this, "桌号输入错误,该桌客人不存在");
}
}
}
public static void main(String args[]) throws Exception {
MainFrame mf = new MainFrame();
//chooseDishes cd = new chooseDishes();
/*DataOperator DO = new DataOperator();
String ans[] = DO.SelectOneItem("select Did from meatdishestable");
for(int i = 0; i < ans.length; i++) {
if(ans[i] == null) {
break;
} else {
System.out.println(ans[i]);
}
}*/
}
}
chooseDishes.java(chooseDishes类,顾客选菜类)
package orderDishes;
/**
* @description 该类实现用户点菜功能
* @author 温雅新
* @date 2016/10/15
*/
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Iterator;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class chooseDishes extends JFrame implements ActionListener, ListSelectionListener {
private String id; //菜品编号
private String name; //菜品名称
private String description; //菜品描述
private String price; //菜品价格
private Image image; //菜品图片
private MyCanvas drawArea = new MyCanvas(); //绘制菜品各种信息的画布
private JLabel dishName; //“菜品名称”的静态文本
private JTextField dishNameText; //显示菜品名称的文本框
private JLabel number; //“菜品份数”的静态文本
private JTextField numberText; //显示菜品份数的文本框
private JButton increaseNumber; //增加菜品份数的按钮
private JButton descreaseNumber; //减少菜品份数的按钮
private JList<String> list1; //list1用来显示菜单
private JList<String> list2; //list2用来显示已选菜品
private DefaultListModel<String> listModel1; //listModel1,listModel2用来构造上面两个list
private DefaultListModel<String> listModel2;
private JButton addDish; //增加菜品,该按钮作用于list1
private JButton removeDish; //移除菜品,该按钮作用于list2
private JButton advice; //推荐菜品,随机为用户推荐三个菜品
private JButton stopChoose; //下单,点击后关闭界面
private String[] Did; //存放该类菜品的编号,信息来源于数据库
private String[] Dname; //存放该类菜品的名称,信息来源于数据库
private String[] Ddescription; //存放该类菜品的描述,信息来源于数据库
private String[] Dprice; //存放该类菜品的价格,信息来源于数据库
private int tableIndex; //当前点菜用户的桌号
private HashSet<String> choosedIdSet = new HashSet<String>(); //已选择菜品编号
private HashSet<String> unChoosedIdSet = new HashSet<String>(); //未选择菜品编号
/**
* @description 该类的构造函数,用来完成该类对象的初始化工作。
* @param num 是从主界面传送进来的当前用户的桌号
* @param type 是从主界面传送进来的菜品类型
* @throws Exception 执行数据库操作出错时抛出异常
*/
public chooseDishes(int num,String type) throws Exception {
//设置窗体标题
this.setTitle("欢迎选菜");
//设置窗体可见,窗体默认不可见,如果不设置窗体是隐身的。
this.setVisible(true);
//选择dispose_on_close的关闭方式。该方式关闭当前窗体而不会连带关闭父窗体
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//vis进行初始化工作,刚开始没有任何菜被选,都初始化为false
tableIndex = num;
choosedIdSet.clear();
unChoosedIdSet.clear();
//窗体布局分为三个部分,用upPanel盛装这部分控件放置窗体北方。
JPanel upPanel = new JPanel();
//设置面板的布局方式为流动布局
FlowLayout fl = new FlowLayout(FlowLayout.CENTER,30,30);
upPanel.setLayout(fl);
//实例化加入面板的各个控件,实例化一个控件后并为相应的控件添加事件监听器
dishName = new JLabel("菜品名称:");
dishNameText = new JTextField(25);
dishNameText.setEditable(false);
number = new JLabel("份数:");
numberText = new JTextField(10);
numberText.setEditable(false);
increaseNumber = new JButton("+");
increaseNumber.addActionListener(this);
descreaseNumber = new JButton("-");
descreaseNumber.addActionListener(this);
//将各个控件添加到upPanel上
upPanel.add(dishName);
upPanel.add(dishNameText);
upPanel.add(number);
upPanel.add(numberText);
upPanel.add(increaseNumber);
upPanel.add(descreaseNumber);
//窗体默认采用bordLayout布局,将该面板放置在窗体上部(窗体北侧)。
this.add(BorderLayout.NORTH,upPanel);
//根据调用该类时传入的菜品类型,对界面的两个列表进行初始化工作。
initListModel(type);
//中部面板主要盛装两个列表和各种点菜的按钮,同样也使用浮动布局
JPanel middlePanel = new JPanel();
FlowLayout fl2 = new FlowLayout(FlowLayout.CENTER,50,10);
middlePanel.setLayout(fl2);
//初始化两个列表,并设定其中项的宽度和高度,设置可视高度,这些控件必须加到ScrollPane里面才能有滚动条
list1 = new JList<String>(listModel1);
list2 = new JList<String>(listModel2);
list1.setFixedCellWidth(220);
list1.setFixedCellHeight(20);
list2.setFixedCellWidth(220);
list2.setFixedCellHeight(20);
list1.setVisibleRowCount(15);
list2.setVisibleRowCount(15);
list1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list1.addListSelectionListener(this);
list2.addListSelectionListener(this);
//欲想让两个列表有滚动条要将它加入到滚动面板中
JScrollPane jScrollPane1 = new JScrollPane(list1);
JScrollPane jScrollPane2 = new JScrollPane(list2);
//实例化四个功能按键,并添加监听器
addDish = new JButton("添加菜品");
addDish.addActionListener(this);
removeDish = new JButton("移除菜品");
removeDish.addActionListener(this);
advice = new JButton("推荐菜品");
advice.addActionListener(this);
stopChoose = new JButton("结束点菜");
stopChoose.addActionListener(this);
Box listBox1 = new Box(BoxLayout.Y_AXIS);
Box listBox2 = new Box(BoxLayout.Y_AXIS);
listBox1.add(Box.createVerticalStrut(20)); //设纵向间距,不至于两个滚动板顶着上方排列
listBox2.add(Box.createVerticalStrut(20));
listBox1.add(jScrollPane1); //listBox1放JScrollPane1
listBox2.add(jScrollPane2); //listBox2放JScrollPanel
Box box1 = Box.createVerticalBox();
box1.add(Box.createVerticalStrut(20));
box1.add(addDish);
box1.add(Box.createVerticalStrut(50));
box1.add(removeDish);
box1.add(Box.createVerticalStrut(50));
box1.add(advice);
box1.add(Box.createVerticalStrut(50));
box1.add(stopChoose);
middlePanel.add(listBox1);
middlePanel.add(box1);
middlePanel.add(listBox2);
this.add(middlePanel);
//drawArea = new MyCanvas();
//drawArea.setValue(name, description, price, image);
//drawArea继承了Canvas类,用来绘制菜品信息,在此设置其大小
drawArea.setPreferredSize(new Dimension(400,450));
//bottomPanel.add(drawArea);
this.add(BorderLayout.SOUTH,drawArea);
this.setBounds(500,50,900,900);
this.setResizable(false);
}
/**
* @description 该方法用来将相应类型的菜品绑定到列表控件中。
* @param arg arg的类型是String,它确定顾客的点餐类型
* @return 空
* @throws Exception
*/
public void initListModel(String arg) throws Exception {
listModel1 = new DefaultListModel<>();
listModel2 = new DefaultListModel<>();
//创建数据库操作对象。
DataOperator DO = new DataOperator();
//获取所有该类菜品的编号
Did = DO.SelectOneItem("select Did from " + arg);
//获取所有该类菜品的名称
Dname = DO.SelectOneItem("select Dname from " + arg);
//获取所有该类菜品的描述
Ddescription = DO.SelectOneItem("select Ddescription from " + arg);
//获取所有该类菜品对应的价格
Dprice = DO.SelectOneItem("select Dprice from " + arg);
//idArray存放该桌客人已经选择的菜的编号
String[] idArray = new String[100];
String[] numArray = new String[100];
//numArray用来存放该桌客人已经选择的菜的数量
idArray = DO.SelectOneItem("select Did from table" + String.valueOf(tableIndex));
numArray = DO.SelectOneItem("select Dnum from table" + String.valueOf(tableIndex));
//把菜品的名称绑定到list1控件上去。
for(int i = 0; i < Dname.length; i++) {
listModel1.addElement(Dname[i]);
unChoosedIdSet.add(Did[i]); //开始都假设这些菜没有选
}
for(int i = 0; i < idArray.length; i++) {
if(idArray[i] == null)
break;
int id = getIndex(Did,idArray[i]);
if(id != -1) {
String temp = Dname[id] + " * " + numArray[i] + "份";
listModel2.addElement(temp);
choosedIdSet.add(Did[id]); //已选菜品编号加入集合
unChoosedIdSet.remove(Did[id]); //将菜移除未选菜品
}
}
}
@Override
public void valueChanged(ListSelectionEvent event) {
// TODO Auto-generated method stub
/*事件源是list1的时候,选中一个菜品,将名称放入顶部菜品名,并
* 设置菜的默认份数是1,并调用drawArea的repaint方法绘制
* 该菜品的名称,价格,描述,图片等信息供用户参考。
*/
if(event.getSource() == list1) {
String temp = list1.getSelectedValue();
if(temp != "") {
dishNameText.setText(temp);
numberText.setText("1");
}
name = list1.getSelectedValue(); //获取名称
int index = getIndex(Dname,name); //获取该菜在数组中的编号,这样就可以确定该菜的其他信息
id = Did[index];
description = Ddescription[index];
price = Dprice[index];
Toolkit toolKit = Toolkit.getDefaultToolkit();
image = toolKit.createImage("pictrue\\" + id + ".png");
drawArea.setValue(name, description, price, image);
drawArea.repaint();
}
}
@Override
public void actionPerformed(ActionEvent event) {
// TODO Auto-generated method stub
//如果事件源是添加菜品
if(event.getSource() == addDish) {
if(list1.getSelectedValue() != "") {
String item = list1.getSelectedValue();
int id = getIndex(Dname,item);
if(id != -1) {
try {
String sql = "select * from table" + String.valueOf(tableIndex) + " where Did='" + Did[id] + "'";
DataOperator DO = new DataOperator();
boolean flag = DO.existInTable(sql);
if(flag == false) { ///记录在数据库中不存在可以添加数据
item += " * " + numberText.getText() + " 份";
listModel2.addElement(item);
int sum = Integer.parseInt(numberText.getText())*Integer.parseInt(Dprice[id]);
sql = "insert into table" + String.valueOf(tableIndex) + "(Did,Dprice,Dnum,Dsum,Dname) values('" + Did[id] + "','" + Dprice[id] + "','" + numberText.getText() + "','" + String.valueOf(sum) + "','" + Dname[id] + "')";
DO.insertRecord(sql); //插入记录
choosedIdSet.add(Did[id]);
unChoosedIdSet.remove(Did[id]);
} else {
JOptionPane.showMessageDialog(this, "该菜品已选过,请选择其他菜品");
}
}catch (Exception ex) {
ex.printStackTrace();
}
}
}
}else if(event.getSource() == removeDish) {
//如果事件源是移除菜品,则我们将list2中选中的菜品移除
if(list2.getSelectedValue() != "") {
String temp = list2.getSelectedValue();
String item = temp.substring(0,temp.indexOf(' '));
int id = getIndex(Dname,item);
DataOperator DO;
try {
DO = new DataOperator();
String sql = "delete from table" + String.valueOf(tableIndex) + " where Did='" + Did[id] + "'";
DO.deleteRecord(sql);
listModel2.removeElementAt(list2.getSelectedIndex()); ///移除
unChoosedIdSet.add(Did[id]); //将菜添加入未选集合
choosedIdSet.remove(Did[id]); //将菜从已选集合删除
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
JOptionPane.showMessageDialog(this,"请选中要删除的菜品");
}
}
else if(event.getSource() == list1) { ///当点中菜品时,显示菜品相关信息。
if(list1.isSelectionEmpty()==false) {
dishNameText.setText(list1.getSelectedValue());
numberText.setText("1");
}
}else if(event.getSource() == increaseNumber) {
//如果点击增加按钮,对应菜的份数增加1.
int num = Integer.parseInt(numberText.getText()); ///把字符串转化成整数
num++;
numberText.setText(String.valueOf(num));
}else if(event.getSource() == descreaseNumber) {
//如果点击减少按钮,对应菜品份数减少1,但是最少是一份
int num = Integer.parseInt(numberText.getText()); ///把字符串转化成整数
if(num > 1) {
num--;
numberText.setText(String.valueOf(num));
}
}else if(event.getSource() == stopChoose) {
//点击结束点菜的时候,关闭窗体
this.dispose();
}else if(event.getSource() == advice) {
//点击推荐点菜的时候,为顾客推荐3种菜
int adviceNumber = 3; ///默认推荐菜品数为3种
int number = unChoosedIdSet.size(); //未选菜品种类
if(number < 3) //未选菜品数目不足三种,则推荐菜品数目就是剩余的菜品数量
adviceNumber = number;
int id;
if(adviceNumber != 0) {
for(int i = 1; i <= adviceNumber; i++) {
number = unChoosedIdSet.size();
id = (int)(Math.random()*number); //随机选取一个未点的菜品
try {
//String sql = "select * from table" + String.valueOf(tableIndex) + " where Did='" + Did[id] + "'";
DataOperator DO = new DataOperator();
//boolean flag = DO.existInTable(sql);
//if(flag == false) { ///记录在数据库中不存在可以添加数据
// String item = Dname[id] + " * " + "1份";
Iterator it = (Iterator) unChoosedIdSet.iterator(); ///获取集合迭代器
int temp = 0;
String item="";
//获取第id个元素
while(it.hasNext()) {
temp++;
if(temp == id) {
item = (String) it.next();
break;
}
}
choosedIdSet.add(item); //该菜品加入已选菜品集合
unChoosedIdSet.remove(item); //该菜品从未选菜品集合中删除
id = getIndex(Did,item);
item = Dname[id] + " * " + "1份";
listModel2.addElement(item);
int sum = Integer.parseInt(Dprice[id]);
String sql = "insert into table" + String.valueOf(tableIndex) + "(Did,Dprice,Dnum,Dsum,Dname) values('" + Did[id] + "','" + Dprice[id] + "','" + "1" + "','" + String.valueOf(sum) + "','" + Dname[id] + "')";
DO.insertRecord(sql);
}catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
}
///该函数用来查询选中菜品在数组中的编号
public int getIndex(String[] stringArray,String elem) {
int id=-1;
for(int i = 0; i < stringArray.length; i++) {
if(elem.equals(stringArray[i])) {
id = i;
break;
}
}
return id;
}
}
showOrderDetail.java(showOrderDetail类,显示消费详情)
package orderDishes;
/**
* @description 该类用来显示用户消费的详情
* @author 温雅新
* @date 2017/10/21
*/
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
public class showOrderDetail extends JFrame {
private JTable table;
private JLabel allMoney;
private JTextField showMoneyText;
private int sum;
public showOrderDetail(int tableIndex) throws Exception {
this.setTitle("消费明细");
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
String sql = "select Dname,Dprice,Dnum,Dsum from table" + String.valueOf(tableIndex);
DataOperator DO = new DataOperator();
table = DO.getTable(sql);
JScrollPane js = new JScrollPane(table);
this.add(js);
int rowNumber = table.getRowCount();
sum = 0;
for(int i = 0; i < rowNumber; i++) {
String temp = String.valueOf(table.getValueAt(i, 3));
sum += Integer.parseInt(temp);
}
JPanel bottomPanel = new JPanel();
FlowLayout fl = new FlowLayout(FlowLayout.RIGHT,20,50);
bottomPanel.setLayout(fl);
allMoney = new JLabel("合计:");
showMoneyText = new JTextField(20);
showMoneyText.setText(String.valueOf(sum));
bottomPanel.add(allMoney);
bottomPanel.add(showMoneyText);
this.add(BorderLayout.SOUTH,bottomPanel);
this.pack();
}
}
DataOperator.java(DataOperator类,该类是数据库操作类)
package orderDishes;
/**
* @description 该类写了许多方法,专门用于数据库操作
* @author 温雅新
* @date 2017/10/21
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class DataOperator {
//mysql数据库驱动
private String driver = "com.mysql.jdbc.Driver";
private String url = "jdbc:mysql://127.0.0.1:3306/dishInfo?useUnicode=true&characterEncoding=utf-8&useSSL=true";
private String user = "root";
private String pass = "root";
private Connection conn = null;
private Statement stmt = null;
//加载驱动,生成连接。
public DataOperator() throws Exception {
Class.forName(driver);
conn = DriverManager.getConnection(url, user, pass);
stmt = conn.createStatement();
}
/**
* @description 该函数用来查询某个表的某个字段的全部值
* @param sql 传入的参数为sql语句
* @return 返回值是某个表某个属性的所有值
* @throws SQLException 抛出数据库操作异常
*/
public String[] SelectOneItem(String sql) throws SQLException {
String[] infoArray = new String[20];
try {
stmt.execute(sql);
ResultSet rs = stmt.getResultSet();
int i = 0;
while(rs.next()) {
infoArray[i++] = rs.getString(1);
}
}catch (Exception ex) {
ex.printStackTrace();
}
return infoArray;
}
/**
* @description 该方法用来判断用户要获取的记录在数据库中是否存在
* @param sql 传入参数为sql语句
* @return 返回值是布尔变量,如果是true代表记录存在,否则记录不存在
* @throws SQLException 数据库操作异常时抛出提示
*/
public boolean existInTable(String sql) throws SQLException {
boolean flag = false;
try {
ResultSet rs = stmt.executeQuery(sql);
int num = 0;
while(rs.next()) {
num++;
}
if(num > 0) //说明查询的记录存在
flag = true;
}catch (Exception ex) {
ex.printStackTrace();
}
return flag;
}
/**
* @description 该方法用来向表中插入一条记录
* @param sql 传入参数为Sql语句
* @throws SQLException 数据库操作出错时抛出异常
*/
public void insertRecord(String sql) throws SQLException {
try {
stmt.execute(sql);
}catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* @description 该方法用来删除表中的一条记录
* @param sql 传入参数为Sql语句
* @throws SQLException 数据库操作出错时抛出异常
*/
public void deleteRecord(String sql) throws SQLException {
try {
stmt.execute(sql);
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* @description 该方法返回用户所需要的一张表
* @param sql 传入参数为sql语句
* @return 返回的时一张用户所需要的表
* @throws SQLException 数据库操作出错时抛出异常
*/
public JTable getTable(String sql) throws SQLException {
ResultSet rs = stmt.executeQuery(sql);
DefaultTableModel model=new DefaultTableModel();
///创建表头
model.setColumnIdentifiers(new Object[]{"菜品名称","价格","份数","总计"});
while(rs.next())
{
String name = rs.getString(1);
String price = rs.getString(2);
String num = rs.getString(3);
String sum = rs.getString(4);
//把以上数据添加到表格模型的一行中
model.addRow(new Object[]{name,price,num,sum});
}
JTable mytable = new JTable(model);
return mytable;
}
/**
* @description 该方法获取用户所需的结果集
* @param sql 传入的参数为Sql语句
* @return 返回值为结果集
* @throws SQLException 数据库操作出错时抛出异常
*/
public ResultSet getResult(String sql) throws SQLException {
ResultSet rs = stmt.executeQuery(sql);
return rs;
}
}
MyCanvas.java (MyCanvas类,主要用于chooseDishes类来绘制菜品信息)
package orderDishes;
import java.awt.Canvas;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
public class MyCanvas extends Canvas {
private String name; //菜品名称
private String description; //菜品描述
private String price; //菜品单价
private Image image; //菜品图片
/**
* @description 该函数实现对该类的各个变量赋值。
* @param _name 菜品名称
* @param _description 菜品描述
* @param _price 菜品单价
* @param _image 菜品图片
*/
public void setValue(String _name,String _description,String _price,Image _image) {
name = _name;
description = _description;
price = _price;
image = _image;
}
//重写paint方法,将菜品的信息绘制到画布上
public void paint(Graphics g) {
Font f = new Font("TimesRoman",Font.BOLD,20);
g.setFont(f);
g.drawString("名称:" + name,200,50);
g.drawString("描述:" + description, 300, 430);
g.drawString("价格:" + price,600,50);
g.drawImage(image, 250, 80, 400, 300,this);
}
}
*******不足之处:初次写对java中变量的命名规范等还不够了解,然后是写之前没有用软件工程的方法来对
整个系统进行一个有条理的设计(只是进行了大概的设计),导致写代码的时候经常缺少东西,然后再去添加,
最后系统写完,填补漏洞也比较费事,代码组织稍有混乱。
*******个人收获:第一次写,大概知道了如何去设计一个系统,经常学习算法再写东西会发现,很多功能写
起来都很简单(可能功能实现不是什么最优算法),也让自己对这些工具使用起来更加熟练。