博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java记账本小项目一(图解超详细)
阅读量:3897 次
发布时间:2019-05-23

本文共 18829 字,大约阅读时间需要 62 分钟。

首先展示一个这个项目的原型:

在这里插入图片描述
有这些各种各样的功能。

首先第一步是创建对应的数据库:

启动mysql 服务,然后连接Navicat
数据库的名字叫做hutubill
在这里插入图片描述
再创建三个表:

  1. 配置表信息 config
    用于保存每月预算和Mysql的安装路径( 用于备份还原用)
  2. 消费分类表 category
    用于保存消费分类,比如餐饮,交通,住宿
  3. 消费记录表 record
    用于存放每一笔的消费记录,并且会用到消费分类
    config有id,key_,value
CREATE TABLE config (  id int ,  key_ varchar(255) ,  value varchar(255) )  ENGINE=InnoDB  DEFAULT CHARSET=utf8;

category 有id,name

CREATE TABLE category (  id int,  name varchar(255))   ENGINE=InnoDB DEFAULT CHARSET=utf8;

record有 id,spend,cid,comment,date

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进行自增长

在这里插入图片描述

最后是增加外键约束

(确定record表的外键是cid,指向了category表的id主键)

alter table record add constraint fk_record_category foreign key (cid) references category(id);

接下来就是对应的原型设计了

在这里插入图片描述
在src下创建HutuMainFrame 这个类
在这里插入图片描述

import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;public class HutuMainFrame {
public static void main(String[] args) {
//用到了JFrame 它是swing的一个组件,是用来创建窗口的 JFrame f=new JFrame(); //应该算是他的大小 f.setSize(500,450); f.setTitle("wzw的一本糊涂账"); //如果组件当前未显示或者 c 为 null,则此窗口将置于屏幕的中央 f.setLocationRelativeTo(null); //这个是判断是否可以调整,false就是不能自动调整 f.setResizable(false); //设置用户在此窗体上发起 "close" 时默认执行的操作 //而EXIT_ON_CLOSE(在 JFrame 中定义):使用 System exit 方法退出应用程序 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //创建按钮 //这个是一个工具栏 JToolBar tb=new JToolBar(); JButton bSpend=new JButton("消费一览"); JButton bRecord=new JButton("记一笔"); JButton bCategory=new JButton("消费分类"); JButton bReport=new JButton("月消费报表"); JButton bConfig=new JButton("设置"); JButton bBackup=new JButton("备份"); JButton bRecover=new JButton("恢复"); //再把这几个按钮都加到工具栏中 tb.add(bSpend); tb.add(bRecord); tb.add(bCategory); tb.add(bReport); tb.add(bConfig); tb.add(bBackup); tb.add(bRecover); //再是位置 这个是默认0边距的,可以改改看 f.setLayout(new BorderLayout()); //这里就是在上面,放这个工具栏 f.add(tb,BorderLayout.NORTH); //这个意思应该是在布局的中间位置,放JPanel f.add(new JPanel(),BorderLayout.CENTER); //再让其可见 f.setVisible(true); //再添加几个按键的功能,也就是监听事件 //消费一览 bSpend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
} }); //记一笔 bRecord.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
} }); //消费分类 bCategory.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
} }); //设置 bConfig.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
} }); //备份 bBackup.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
} }); //恢复 bRecover.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
} }); }}

但这还不是完全的,在JPanel以及之后的监听器事件上,都会做相应的添加。

进行界面规划之后,大致需要分成以下几个包,和包里各自的类,现在先给这个包

在这里插入图片描述

首先第一个是在面板类中,为了方便监听器选择对应的值,

把组件声明为public的属性, 把面板类设计为单例模式
这里使用最简单的单例模式
直接声明一个SpendPanel类型的静态属性,并指向当前实例
SpendPanel 类

package gui.panel;import javax.swing.*;public class SpendPanel {
//这里就是创建一个对象 为什么可以直接getInstance //是因为 他是instance吗, 我等下改成别的试试看 public static SpendPanel instance=new SpendPanel(); //JLabel 就是一个可以显示图像和文本的标签 JLabel lMonthSpend =new JLabel("本月消费"); JLabel lTodaySpend =new JLabel("今日消费"); JLabel lAvgSpendPerDay=new JLabel("日均消费"); JLabel lMonthLeft =new JLabel("本月剩余"); JLabel lDayAvgAvailable =new JLabel("日均可用"); JLabel lMonthLeftDay=new JLabel("距离月末"); //这个相当于是设置初始值吗 JLabel vMonthSpend =new JLabel("¥2300"); JLabel vTodaySpend =new JLabel("¥25"); JLabel vAvgSpendPerDay=new JLabel("¥120"); JLabel vMonthLeft =new JLabel("¥2084"); JLabel vDayAvgAvailable =new JLabel("¥389"); JLabel vMonthLeftDay=new JLabel("15天"); //然后这边就是 私有化构造方法使得该类无法在外部通过new 进行实例化 private SpendPanel(){
}}

再又写一个用于居中的面板 CenterPanel继承了JPanel

package util;import javax.swing.*;import java.awt.*;public class CenterPanel extends JPanel {
//这个继承居然没有要写的东西 private double rate;//拉伸的比例 private JComponent c;//显示的组件 private boolean strech;//是否拉伸 //再写一个构造函数 public CenterPanel(double rate, boolean strech) {
//将容器的布局设为绝对布局,也就是固定大小 this.setLayout(null); this.rate = rate; this.strech = strech; } //还有一个构造器 public CenterPanel(double rate) {
this(rate, true);//调用了上一个构造器 } //然后是repaint方法会使用绝对定位的方式把组件放在中间位置 //如果strech是true,就会根据整个容器的大小,设置组件的大小,达到拉伸的效果 //如果strech是false, 就使用组件的preferredSize,即非拉伸效果。 public void repaint() {
if (null != c) {
//如果组件不为空,this就是这个继承JPanel 的类 Dimension containerSize = this.getSize(); //相当于是获得预尺寸 Dimension componentSize = c.getPreferredSize(); if (strech)//可以拉伸的 c.setSize((int)(containerSize.width*rate),(int)(containerSize.height*rate)); else c.setSize(componentSize); //再设置位置 setSize在上一步已经确定好拉不拉伸了 c.setLocation(containerSize.width/2-c.getSize().width/2,containerSize.height/2-c.getSize().height/2); } super.repaint(); } //再是show方法 // 先把这个容器中的组件都移出,然后把新的组件加进来,并且调用updateUI进行界面渲染。 //参数是新的组件p public void show(JComponent p){
this.c=p; //开始移组件 Component[] cs=getComponents(); for(Component c:cs){
remove(c); } //再把新的加进来 add(p); //再进行升级 this.updateUI(); } //开始调用主函数 public static void main(String[] args) {
JFrame f=new JFrame(); f.setSize(200,200); //设置窗口相对于指定组件的位置。 //如果组件当前未显示或者 c 为 null,则此窗口将置于屏幕的中央 f.setLocationRelativeTo(null); //意思是需要进行拉伸 CenterPanel cp=new CenterPanel(0.85,true); //为什么会有这个set方法呢,是content,而不是自己新建的 f.setContentPane(cp); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); JButton b=new JButton("abc"); cp.show(b); }}

再创建一个工具类GUIUtil

package util;import javax.swing.*;import java.awt.*;import java.io.File;public class GUIUtil {
//这个到时候改 private static String imageFolder="e:/project/HuTuZhang/img"; //给按钮设置图标和文本以及提示文字 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); } //Component...这是什么意思 public static void setColor(Color color,JComponent... cs){
for(JComponent c:cs){
//这个是背景的颜色吗 c.setForeground(color); } } //这里的拉伸比例1表示满屏幕 public static void showPanel(JPanel p,double strechRate){
//这个方法之后会操作的 GUIUtil.useLNF(); JFrame f=new JFrame(); f.setSize(500,500); f.setLocationRelativeTo(null); CenterPanel cp=new CenterPanel(strechRate); f.setContentPane(cp); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); cp.show(p); } //然后还有一个默认的,参数只有JPanel public static void showPanel(JPanel p){
showPanel(p,0.85); } //先写一个判断输入框内容是否为空的 public static boolean checkEmpty(JTextField tf,String input){
//trim修剪 删去部分空白 String text=tf.getText().trim(); if(0==text.length()){
//如果长度是0 的话 //JOptionPane是消息提示框 JOptionPane.showMessageDialog(null,input+"不能为空"); //说是什么聚焦窗口 也不知道有什么用 tf.grabFocus(); return false; } return true; } //校验一个组件内容是否是数字格式 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 e1){
//这里就抛出数字格式异常 //出现消息提示框 JOptionPane.showMessageDialog(null,input+"需要是整数"); tf.grabFocus(); return false; } } //判断一个组件的内容是否为零 public static boolean checkZero(JTextField tf,String input){
if(!checkNumber(tf,input)) return false; String text=tf.getText().trim(); if(0==Integer.parseInt(text)){
//如果换算出来的整数就是0的话 JOptionPane.showMessageDialog(null,input+"不能为零"); tf.grabFocus(); return false; } return true; } //这里又写了一个方法用来设置水晶皮肤 public static void useLNF(){
try{
javax.swing.UIManager.setLookAndFeel("com.birosoft.liquid.LiquidLookAndFeel"); }catch (Exception e){
e.printStackTrace(); } }}

这里有一个水晶皮肤的jar文件,需要的可以私信我发给你:

需要把这个包导入到项目中:
导入方法:file->Project Structure
然后Modules -> Dependencies -> “+” -> “Jars or directories”
最后 apply->ok

=

然后可以写代码测试一下:

import util.CenterPanel;import util.GUIUtil;import javax.swing.*;import java.security.Guard;public class Test {
public static void main(String[] args) {
GUIUtil.useLNF(); JPanel p=new JPanel(); p.add(new JButton("按钮1")); p.add(new JButton("按钮2")); //默认是0.85的 GUIUtil.showPanel(p); }}

结果显示:

在这里插入图片描述
这边的话,不想用这个插件,也可以改成

javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

然后是集合了颜色的工具类:

package util;import java.awt.*;public class ColorUtil {
//Color来自Integer.decode public static Color blueColor= Color.decode("#3399FF"); public static Color garyColor= Color.decode("#999999"); public static Color backgroundColor= Color.decode("#eeeeee"); public static Color warningColor= Color.decode("#FF3333"); //这个方法是根据进度来显示不同的颜色 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; }}

还有一个环形进度条的工具

package util; import java.awt.BasicStroke;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.RenderingHints;import java.awt.event.ActionEvent;import java.awt.event.ActionListener; import javax.swing.JButton;import javax.swing.JPanel;import javax.swing.SwingWorker; 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%"; } 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(); } }

这个也可以写一个测试代码来运行一下:

package test;  import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;  import javax.swing.JButton;import javax.swing.JPanel;import javax.swing.SwingWorker;  import util.CircleProgressBar;import util.ColorUtil;import util.GUIUtil;  public class Test {
public static void main(String[] args) {
GUIUtil.useLNF(); //面板 JPanel p = new JPanel(); //进度条组件 CircleProgressBar cpb = new CircleProgressBar(); cpb.setBackgroundColor(ColorUtil.blueColor); cpb.setProgress(0); //按钮 JButton b = new JButton("点击"); //添加组件 p.setLayout(new BorderLayout()); p.add(cpb, BorderLayout.CENTER); p.add(b, BorderLayout.SOUTH); //显示面板 GUIUtil.showPanel(p); //给按钮加监听 b.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
new SwingWorker() {
@Override protected Object doInBackground() throws Exception {
for (int i = 0; i < 100; i++) {
cpb.setProgress(i + 1); cpb.setForegroundColor(ColorUtil.getByPercentage(i + 1)); try {
Thread.sleep(100); } catch (InterruptedException e1) {
// TODO Auto-generated catch block e1.printStackTrace(); } } return null; } }.execute(); } }); }}

在这里插入图片描述

然后是生成柱状图的工具,这个也需要导入一个chart.jar文件,需要的可以私聊我

package util; import java.awt.Color;import java.awt.Font;import java.awt.Image; import javax.swing.Icon;import javax.swing.ImageIcon;import javax.swing.JLabel;import javax.swing.JPanel; import com.objectplanet.chart.BarChart;import com.objectplanet.chart.Chart; 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; } 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); } }

然后就是几张图片,需要的私聊我,放在之前定义好的位置上,我是放在:

e:/project/HuTuZhang/img

在这里插入图片描述

转载地址:http://ysfen.baihongyu.com/

你可能感兴趣的文章
【转】结构体中Char a[0]用法——柔性数组
查看>>
结构体最后定义一个char p[0];这样的成员有何意义(转)
查看>>
一步一学Linux与Windows 共享文件Samba (v0.2b)
查看>>
Linux 下忘记root密码怎么办
查看>>
Linux软件下载源码编程文章资料周立发--之调试
查看>>
GIT分支管理是一门艺术
查看>>
Cscope在emacs中的配置与使用
查看>>
emacs 2.4安装问题 ecb
查看>>
ecb里使用自定义快捷键切换窗口
查看>>
vim(gvim)支持对齐线
查看>>
CentOS编译安装Lighttpd1.4.28
查看>>
实践HTTP206状态:部分内容和范围请求
查看>>
【C++基础】拷贝构造函数的参数必须是引用类型
查看>>
【C++基础】virtual析构函数
查看>>
【Java基础】面向对象
查看>>
【Java.Web】web.xml详解
查看>>
J2EE的技术体系
查看>>
【Java.Web】Java Web应用程序的规范目录结构,*WEB组件的URL/入口*
查看>>
【基础篇】计算机网络
查看>>
OSI 7层详解
查看>>