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

有这些各种各样的功能。

首先第一步是创建对应的数据库:
启动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);//这个意思应该是在布局的中间位置,放JPanelf.add(new JPanel(),BorderLayout.CENTER);//再让其可见f.setVisible(true);//再添加几个按键的功能,也就是监听事件//消费一览bSpend.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e){}});//记一笔bRecord.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {}});//消费分类bCategory.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {}});//设置bConfig.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {}});//备份bBackup.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {}});//恢复bRecover.addActionListener(new ActionListener() {@Overridepublic 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));elsec.setSize(componentSize);//再设置位置 setSize在上一步已经确定好拉不拉伸了c.setLocation(containerSize.width/2-c.getSize().width/2,containerSize.height/2-c.getSize().height/2);}super.repaint();}//再是show方法// 先把这个容器中的组件都移出,然后把新的组件加进来,并且调用updateUI进行界面渲染。//参数是新的组件ppublic 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);}//然后还有一个默认的,参数只有JPanelpublic 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.decodepublic 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() {@Overridepublic void actionPerformed(ActionEvent e) {new SwingWorker() {@Overrideprotected 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 blocke1.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

Java记账本小项目一(图解超详细)相关推荐

  1. Java记账本小项目二(图解超详细)

    继续上一篇博客,博客地址在这:https://blog.csdn.net/qq_41115379/article/details/112795150 接下来根据功能演示如何开发一个一个的Panel M ...

  2. java小项目之贪吃蛇项目(图解超详细)

    在刷视频的时候,看到了一个讲解用java写一个贪吃蛇的项目,于是想照猫画虎的学习仿制一下. 学习视频的地址:https://www.bilibili.com/video/BV1HE41127CV 也欢 ...

  3. idea(中英文版)java新建一个运行项目到类(超详细)

    使用idea时候要新建一个项目,这个是下载了中文的一个插件,如果是英文原版的对照着位置进行操作即可. 这里的步骤就是新建一个空项目(第1-4步)----新建一个新模块(第5-7步)---新建一个包(第 ...

  4. 2020 从0到1搭建个人博客网站,图解超详细!(附带软件资源)

    2020从0到1搭建个人博客网站,图解超详细!(附带软件资源) 前言 一.准备工作 1.1 入门知识 1.2 所需软件 1.3 软件下载 总结 二.购买域名及安装软件 2.1 购买域名 2.2 安装软 ...

  5. WIN10使用YOLOX训练自己的数据集(图解超详细)

    文章目录 WIN10使用YOLOX训练自己的数据集(图解超详细) 下载YOLOX源码 配置环境,修改源码 添加权重文件 建立VOCdevkit文件夹 添加数据集 划分训练集和测试集 修改 类别 为自己 ...

  6. 上传项目到GitHub(超详细)

    上传项目到GitHub(超详细) 大家好,今天我们来学习一下如何把本地项目上传到GitHub ,好好看,好好学,超详细的 第一步 注册github账号 第二步 下载一个git工具并安装 第三步 注册好 ...

  7. Pyside2 学习系列二:PyInstaller打包项目exe (超详细的Pyside2 攻略)

    继上一篇文章创建了项目后,本章我们进行项目的打包工作. 本项目的所有演示代码:github可在这里下载. 打包只用的工具为PyInstaller. 打包步骤 1 准备环境 1.1 安装`PyInsta ...

  8. java gui 项目解密,java GUI(实例小项目--列出磁盘目录)

    //java实例小项目:列出磁盘目录. import java.awt.*; import java.awt.event.*; import java.io.File; class MyWindDem ...

  9. Java综合练习小项目——快递柜

    快递柜 前言 这是针对基础部分的综合练习,需要了解的知识有变量.数据类型.数组. 取快递是现在大部分人都会做的事情,那么小白该怎么写出一个简单的取快递的程序呢?那么请按照以下功能条件来写出一个简单的快 ...

最新文章

  1. c语言spi发送12位数据,【51单片机】普通I/O口模拟SPI口C语言程序
  2. struts-Result- Configuration
  3. Java 集合系列11: Hashtable深入解析(1)
  4. matplotlib画图设置线条透明度
  5. python xlrd_python读取excel(xlrd)
  6. C++工作笔记-对纯虚函数的进一步理解(作用)
  7. MOV指令在32位汇编程序和64位汇编程序下的相同与不同之处
  8. 信息学奥赛一本通C++语言——1102: 与指定数字相同的数的个数
  9. 标准正态均一性检验 matlab程序,多种均一性检验方法比较研究
  10. pixhawk学习笔记-----mavlink
  11. 杭电1874畅通工程续
  12. 老李分享:持续集成学好jenkins之Git和Maven配置
  13. 一个简单实用的boost升压电路
  14. FIT2CLOUD飞致云成为Kubernetes认证服务提供商(KCSP)
  15. 《犹太人想的和你不一样》
  16. Android9 点击按键KeyEvent.KEYCODE_CAMERA没反应
  17. 使用MapWinGis ActiveX控件在图层上画点
  18. Linux操作系统基础知识命令参数详解
  19. c语言change函数用法,通过值和引用函数
  20. 【PCB Layout】信号抗干扰经验总结

热门文章

  1. GNOME Commander: Linux文件管理器
  2. 95---Python 直角坐标系下绘制双曲螺旋线
  3. OCX控件的注册卸载,以及判断是否注册
  4. 从0了解矩阵——矩阵的本质
  5. 基于ESP8266与Blinker(点灯科技平台)的智能遥控器设计
  6. Win7 未识别网络 的20种常见解决方案
  7. VIVO可能在某一段时间内手机充电数据线上并没有ID脚
  8. 太美医疗科技CTMS临床试验项目管理系统的全新升级
  9. 【JMX】-----JMX概述
  10. CryEnging5.5源码+编辑器完全编译(2018-9-30)