PS:學習完JavaSE基礎后,需要有一個項目來測試自己的學習成果,並加以鞏固。所以在這里,就讓我們來學習下“一本糊塗賬”項目吧。(此項目來源於 Java自學網站)
項目完成效果圖一覽
起始--新建項目
新建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也不用愁沒資源了。下面貼出項目框架圖