PS:学习完JavaSE基础后,需要有一个项目来测试自己的学习成果,并加以巩固。所以在这里,就让我们来学习下“一本糊涂账”项目吧。
项目完成效果图一览
起始--新建项目
新建JavaEEApplication项目,并命名为“yc_hutubill”。并添加lib、classes、img文件夹。效果如下图:
并将classes文件夹作为编译后类的输出目录:
起始--表结构的设计
SQL语句:
#创建config表
use hutubill;
CREATE TABLE config
(
id int,
key_ VARCHAR (255),
value VARCHAR (255)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
#创建消费分类表category
create table category
(
id int,
name varchar(255)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
#创建消费记录表
create table record
(
id int,
spend int,
cid int,
comment varchar(255),
date Date
) ENGINE=INNODB DEFAULT CHARSET=utf8;
#加上主键约束
alter table category add constraint pk_category_id primary key (id);
alter table record add constraint pk_record_id primary key (id);
alter table config add constraint pk_config_id primary key (id);
#设置id自动增长
alter table category change id id int auto_increment;
alter table record change id id int auto_increment;
alter table config change id id int auto_increment;
#设置外键
alter table record add constraint fk_record_category foreign key (cid) references category(id);
旅途--原型设计
原型设计指的是,先把界面做出来,假面上的数据都是假数据,并不是从数据库里读出来的真实数据。之所以这么做,是因为,有了界面,才直观,我们对项目的规划才更有感觉,更重要的是,有了界面,才能更有效地个客户沟通,哪些功能需要修改,哪些功能可以删减。
居中面板
Swing并没有提供一种可以很简单就可以居中的布局器,但是这样的布局器又非常的常见,所以我们就需要开发一个居中面板的类:
package util;
import gui.panel.WorkingPanel;
import javax.swing.*;
import java.awt.*;
/**
* @ClassName: CenterPanel
* @Description:居中布局面板类
* @author: yunche
* @date: 2018/07/19
*/
public class CenterPanel extends JPanel
{
/**
* 拉伸比例
*/
private double rate;
/**
* 显示的组件
*/
private JComponent c;
/**
* 是否拉伸
*/
private boolean stretch;
public CenterPanel(double rate, boolean stretch)
{
this.setLayout(null);
this.rate = rate;
this.stretch = stretch;
}
public CenterPanel(double rate)
{
this(rate, true);
}
@Override
public void repaint()
{
if (null != c)
{
Dimension containerSize = this.getSize();
Dimension componentSize = c.getPreferredSize();
if (stretch)
{
c.setSize((int) (containerSize.width * rate), (int) (containerSize.height * rate));
}
else
{
c.setSize(componentSize);
}
c.setLocation(containerSize.width / 2 - c.getSize().width / 2, containerSize.height / 2 - c.getSize().height / 2);
}
super.repaint();
}
/**
* 展示居中布局的面板
* @param p
*/
public void show(JComponent p)
{
this.c = p;
Component[] cs = getComponents();
for (Component c : cs)
{
remove(c);
}
add(p);
if (p instanceof WorkingPanel)
{
((WorkingPanel) p).updateData();
}
this.updateUI();
}
}
里面涉及到的抽象类WorkingPanel,是用于提供面板的共性方法的,如注册监听器、更新数据等操作:
package gui.panel;
import javax.swing.*;
/**
* @ClassName: WorkingPanel
* @Description: 抽象类用于让子类重写必要的方法
* @author: yunche
* @date: 2018/07/23
*/
public abstract class WorkingPanel extends JPanel
{
/**
* 更新数据
*/
public abstract void updateData();
/**
* 注册监听器
*/
public abstract void addListener();
}
GUIUtil工具类
这个工具类可以帮助我们封装一些后面项目中会用到的常用的操作,代码如下:
package util;
import javax.swing.*;
import java.awt.*;
import java.io.File;
/**
* @ClassName: GUIUtil
* @Description: 专门处理图形界面的工具类
* @author: yunche
* @date: 2018/07/19
*/
public class GUIUtil
{
/**
* 图片的文件夹路径
*/
private static String imageFolder = "META-INF/img";
/**
* 设置按钮的图标
*
* @param b 按钮
* @param fileName 图标名
* @param tip 提示文本
*/
public static void setImageIcon(JButton b, String fileName, String tip)
{
ImageIcon i = new ImageIcon(new File(imageFolder, fileName).getAbsolutePath());
b.setIcon(i);
b.setPreferredSize(new Dimension(61, 81));
b.setToolTipText(tip);
b.setVerticalTextPosition(JButton.BOTTOM);
b.setHorizontalTextPosition(JButton.CENTER);
b.setText(tip);
}
/**
* 设置控件的前景色
*
* @param color
* @param cs
*/
public static void setColor(Color color, JComponent... cs)
{
for (JComponent c : cs)
{
c.setForeground(color);
}
}
/**
* 根据拉伸比例缩放展示面板
*
* @param p 面板
* @param stretchRate 拉伸比例
*/
public static void showPanel(JPanel p, double stretchRate)
{
GUIUtil.useLNF();
JFrame f = new JFrame();
f.setSize(500, 500);
f.setLocationRelativeTo(null);
CenterPanel cp = new CenterPanel(stretchRate);
f.setContentPane(cp);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
cp.show(p);
}
public static void showPanel(JPanel p)
{
showPanel(p, 0.85);
}
/**
* 检查文本输入是否是数字
* 若是数字,则通过检查返回true,否则返回false
*
* @param tf
* @param input
* @return
*/
public static boolean checkNumber(JTextField tf, String input)
{
if (!checkEmpty(tf, input))
{
return false;
}
String text = tf.getText().trim();
try
{
Integer.parseInt(text);
return true;
}
catch (NumberFormatException ne)
{
JOptionPane.showMessageDialog(null, input + " 需要是整数");
tf.grabFocus();
return false;
}
}
/**
* 检查文本框中的内容的是否为0
* 若为0,通不过检查返回false,不为0,通过检查返回true
*
* @param tf
* @param input
* @return
*/
public static boolean checkZero(JTextField tf, String input)
{
if (!checkNumber(tf, input))
{
return false;
}
String text = tf.getText().trim();
if (0 == Integer.parseInt(text))
{
JOptionPane.showMessageDialog(null, input + "不能为零");
tf.grabFocus();
return false;
}
return true;
}
/**
* 检查是文本框的内容是否为空
* 若为空,则显示对话框,提示消息“不能为空”
* 不为空,则返回true
*
* @param tf
* @param input
* @return
*/
public static boolean checkEmpty(JTextField tf, String input)
{
String text = tf.getText().trim();
if (0 == text.length())
{
JOptionPane.showMessageDialog(null, input + "不能为空");
tf.grabFocus();
return false;
}
return true;
}
/**
* 将文本转化为整型数字
*
* @param tf
* @return 转化后的整型数字
*/
public static int getInt(JTextField tf)
{
return Integer.parseInt(tf.getText());
}
/**
* 使用水晶皮肤
*/
public static void useLNF()
{
try
{
javax.swing.UIManager.setLookAndFeel("com.birosoft.liquid.LiquidLookAndFeel");
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 测试效果代码
* 去掉注释后可用
* @param args
public static void main(String[] args)
{
GUIUtil.useLNF();
JPanel p = new JPanel();
p.add(new JButton("按钮1"));
p.add(new JButton("按钮2"));
GUIUtil.showPanel(p);
}
*/
}
里面的用到的水晶皮肤需要导入liquidlnf.jar包,所有后面项目用到的jar包到放在网盘上,请对应下载(若有失效,请到Java自学网站上下载)。
ColorUtil工具类
package util;
import java.awt.*;
/**
* @ClassName: ColorUtil
* @Description: 颜色工具类
* @author: yunche
* @date: 2018/07/20
*/
public class ColorUtil
{
public static Color blueColor = Color.decode("#3399FF");
public static Color grayColor = Color.decode("#999999");
public static Color backgroundColor = Color.decode("#eeeeee");
public static Color warningColor = Color.decode("#FF3333");
/**
* 根据进度条的百分比来改变颜色
*
* @param per
* @return
*/
public static Color getByPercentage(int per)
{
if (per > 100)
{
per = 100;
}
int r = 51;
int g = 255;
int b = 51;
float rate = per / 100f;
r = (int) ((255 - 51) * rate + 51);
g = 255 - r + 51;
Color color = new Color(r, g, b);
return color;
}
}
CircleProgressBar
package util;
import javax.swing.*;
import java.awt.*;
/**
* @ClassName: CircleProgressBar
* @Description: 消费一览圆形进度条
* @author: yunche
* @date: 2018/07/20
*/
public class CircleProgressBar extends JPanel
{
private int minimumProgress;
private int maximumProgress;
private int progress;
private String progressText;
private Color backgroundColor;
private Color foregroundColor;
public CircleProgressBar()
{
minimumProgress = 0;
maximumProgress = 100;
progressText = "0%";
}
@Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D graphics2d = (Graphics2D) g;
// 开启抗锯齿
graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x = 0;
int y = 0;
int width = 0;
int height = 0;
int fontSize = 0;
if (getWidth() >= getHeight())
{
x = (getWidth() - getHeight()) / 2 + 25;
y = 25;
width = getHeight() - 50;
height = getHeight() - 50;
fontSize = getWidth() / 8;
}
else
{
x = 25;
y = (getHeight() - getWidth()) / 2 + 25;
width = getWidth() - 50;
height = getWidth() - 50;
fontSize = getHeight() / 8;
}
graphics2d.setStroke(new BasicStroke(20.0f));
graphics2d.setColor(backgroundColor);
graphics2d.drawArc(x, y, width, height, 0, 360);
graphics2d.setColor(foregroundColor);
graphics2d.drawArc(x, y, width, height, 90,
-(int) (360 * ((progress * 1.0) / (maximumProgress - minimumProgress))));
graphics2d.setFont(new Font("黑体", Font.BOLD, fontSize));
FontMetrics fontMetrics = graphics2d.getFontMetrics();
int digitalWidth = fontMetrics.stringWidth(progressText);
int digitalAscent = fontMetrics.getAscent();
graphics2d.setColor(foregroundColor);
graphics2d.drawString(progressText, getWidth() / 2 - digitalWidth / 2, getHeight() / 2 + digitalAscent / 2);
}
public int getProgress()
{
return progress;
}
public void setProgress(int progress)
{
if (progress >= minimumProgress && progress <= maximumProgress)
{
this.progress = progress;
}
if (progress > maximumProgress)
{
this.progress = maximumProgress;
}
this.progressText = String.valueOf(progress + "%");
this.repaint();
}
public Color getBackgroundColor()
{
return backgroundColor;
}
public void setBackgroundColor(Color backgroundColor)
{
this.backgroundColor = backgroundColor;
this.repaint();
}
public Color getForegroundColor()
{
return foregroundColor;
}
public void setForegroundColor(Color foregroundColor)
{
this.foregroundColor = foregroundColor;
this.repaint();
}
}
ChartUtil
package util;
import com.objectplanet.chart.BarChart;
import com.objectplanet.chart.Chart;
import javax.swing.*;
import java.awt.*;
/**
* @ClassName: CharUtil
* @Description: 图表工具类
* @author: yunche
* @date: 2018/07/20
*/
public class ChartUtil
{
public static int max(double[] sampleValues)
{
int max = 0;
for (double v : sampleValues)
{
if (v > max)
{
max = (int) v;
}
}
return max;
}
private static String[] sampleLabels()
{
String[] sampleLabels = new String[30];
for (int i = 0; i < sampleLabels.length; i++)
{
if (0 == i % 5)
{
sampleLabels[i] = String.valueOf(i + 1 + "日");
}
}
return sampleLabels;
}
public static Image getImage(int width, int height)
{
// 模拟样本数据
double[] sampleValues = sampleValues();
// 下方显示的文字
String[] sampleLabels = sampleLabels();
// 样本中的最大值
int max = max(sampleValues);
// 数据颜色
Color[] sampleColors = new Color[]{ColorUtil.blueColor};
// 柱状图
BarChart chart = new BarChart();
// 设置样本个数
chart.setSampleCount(sampleValues.length);
// 设置样本数据
chart.setSampleValues(0, sampleValues);
// 设置文字
chart.setSampleLabels(sampleLabels);
// 设置样本颜色
chart.setSampleColors(sampleColors);
// 设置取值范围
chart.setRange(0, max * 1.2);
// 显示背景横线
chart.setValueLinesOn(true);
// 显示文字
chart.setSampleLabelsOn(true);
// 把文字显示在下方
chart.setSampleLabelStyle(Chart.BELOW);
// 样本值的字体
chart.setFont("rangeLabelFont", new Font("Arial", Font.BOLD, 12));
// 显示图例说明
chart.setLegendOn(true);
// 把图例说明放在左侧
chart.setLegendPosition(Chart.LEFT);
// 图例说明中的文字
chart.setLegendLabels(new String[]{"月消费报表"});
// 图例说明的字体
chart.setFont("legendFont", new Font("Dialog", Font.BOLD, 13));
// 下方文字的字体
chart.setFont("sampleLabelFont", new Font("Dialog", Font.BOLD, 13));
// 图表中间背景颜色
chart.setChartBackground(Color.white);
// 图表整体背景颜色
chart.setBackground(ColorUtil.backgroundColor);
// 把图表转换为Image类型
Image im = chart.getImage(width, height);
return im;
}
private static double[] sampleValues()
{
double[] result = new double[30];
for (int i = 0; i < result.length; i++)
{
result[i] = (int) (Math.random() * 300);
}
return result;
}
/**
* 测试方法去掉注释可用
* @param args
public static void main(String[] args)
{
JPanel p = new JPanel();
JLabel l = new JLabel();
Image img = ChartUtil.getImage(400, 300);
Icon icon = new ImageIcon(img);
l.setIcon(icon);
p.add(l);
GUIUtil.showPanel(p);
}
*/
}
测试方法效果图:
界面类
就到这里吧,如果有兴趣的,可以去Java自学网站深入学习这个项目,这个网站挺不错的,自学java也不用愁没资源了。下面贴出项目框架图