Java记账本小项目一(图解超详细)
首先展示一个这个项目的原型:
有这些各种各样的功能。
首先第一步是创建对应的数据库:
启动mysql 服务,然后连接Navicat
数据库的名字叫做hutubill
再创建三个表:
- 配置表信息 config
用于保存每月预算和Mysql的安装路径( 用于备份还原用) - 消费分类表 category
用于保存消费分类,比如餐饮,交通,住宿 - 消费记录表 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记账本小项目一(图解超详细)相关推荐
- Java记账本小项目二(图解超详细)
继续上一篇博客,博客地址在这:https://blog.csdn.net/qq_41115379/article/details/112795150 接下来根据功能演示如何开发一个一个的Panel M ...
- java小项目之贪吃蛇项目(图解超详细)
在刷视频的时候,看到了一个讲解用java写一个贪吃蛇的项目,于是想照猫画虎的学习仿制一下. 学习视频的地址:https://www.bilibili.com/video/BV1HE41127CV 也欢 ...
- idea(中英文版)java新建一个运行项目到类(超详细)
使用idea时候要新建一个项目,这个是下载了中文的一个插件,如果是英文原版的对照着位置进行操作即可. 这里的步骤就是新建一个空项目(第1-4步)----新建一个新模块(第5-7步)---新建一个包(第 ...
- 2020 从0到1搭建个人博客网站,图解超详细!(附带软件资源)
2020从0到1搭建个人博客网站,图解超详细!(附带软件资源) 前言 一.准备工作 1.1 入门知识 1.2 所需软件 1.3 软件下载 总结 二.购买域名及安装软件 2.1 购买域名 2.2 安装软 ...
- WIN10使用YOLOX训练自己的数据集(图解超详细)
文章目录 WIN10使用YOLOX训练自己的数据集(图解超详细) 下载YOLOX源码 配置环境,修改源码 添加权重文件 建立VOCdevkit文件夹 添加数据集 划分训练集和测试集 修改 类别 为自己 ...
- 上传项目到GitHub(超详细)
上传项目到GitHub(超详细) 大家好,今天我们来学习一下如何把本地项目上传到GitHub ,好好看,好好学,超详细的 第一步 注册github账号 第二步 下载一个git工具并安装 第三步 注册好 ...
- Pyside2 学习系列二:PyInstaller打包项目exe (超详细的Pyside2 攻略)
继上一篇文章创建了项目后,本章我们进行项目的打包工作. 本项目的所有演示代码:github可在这里下载. 打包只用的工具为PyInstaller. 打包步骤 1 准备环境 1.1 安装`PyInsta ...
- java gui 项目解密,java GUI(实例小项目--列出磁盘目录)
//java实例小项目:列出磁盘目录. import java.awt.*; import java.awt.event.*; import java.io.File; class MyWindDem ...
- Java综合练习小项目——快递柜
快递柜 前言 这是针对基础部分的综合练习,需要了解的知识有变量.数据类型.数组. 取快递是现在大部分人都会做的事情,那么小白该怎么写出一个简单的取快递的程序呢?那么请按照以下功能条件来写出一个简单的快 ...
最新文章
- c语言spi发送12位数据,【51单片机】普通I/O口模拟SPI口C语言程序
- struts-Result- Configuration
- Java 集合系列11: Hashtable深入解析(1)
- matplotlib画图设置线条透明度
- python xlrd_python读取excel(xlrd)
- C++工作笔记-对纯虚函数的进一步理解(作用)
- MOV指令在32位汇编程序和64位汇编程序下的相同与不同之处
- 信息学奥赛一本通C++语言——1102: 与指定数字相同的数的个数
- 标准正态均一性检验 matlab程序,多种均一性检验方法比较研究
- pixhawk学习笔记-----mavlink
- 杭电1874畅通工程续
- 老李分享:持续集成学好jenkins之Git和Maven配置
- 一个简单实用的boost升压电路
- FIT2CLOUD飞致云成为Kubernetes认证服务提供商(KCSP)
- 《犹太人想的和你不一样》
- Android9 点击按键KeyEvent.KEYCODE_CAMERA没反应
- 使用MapWinGis ActiveX控件在图层上画点
- Linux操作系统基础知识命令参数详解
- c语言change函数用法,通过值和引用函数
- 【PCB Layout】信号抗干扰经验总结