小结
这算是我第一个比较完整的项目吧,虽然项目不大,但还是有所收获,发现了一些之前未知的工具、领域以及方法。在最后答辩的时候,发现了更好的写前端的方式(JavaFX)。本次我自己总的缺点有: 类的设计不够好,不能很好地使用抽象类,造成复用和维护的复杂性比较高,还有界面之间的切换不够滑畅。界面的图片和按钮以及风格设计做起来虽然有趣,但是太累了。要好好学下设计模式。
部分效果图
先上部分效果图(我做的是管理员模块):
管理员主菜单界面
开户界面
冻结界面
查询交易界面
下面写一些设计界面的细节
描述1:JFrame去掉窗口修饰,增加背景图片,并且还能继续拖动窗口。
package test;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
/**
* @Title: JFrameDemo.java
* @Package test
* @Description: JFrame去掉窗口修饰,增加背景图片,并且还能继续拖动窗口。
* @author Cqh_i
* @date 2018年10月31日 下午6:59:07
*/
public class JFrameDemo extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel imagePanel;//用来指向内容窗格
//用于处理拖动事件
int xOld = 0;//表示鼠标按下时的x坐标,相对于JFrameDemo
int yOld = 0;//表示鼠标按下时的y坐标,相对于JFrameDemo
public JFrameDemo() {
/*
* 实现窗口拖动事件
*/
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
//按住鼠标按住时,记下旧坐标(相对于JFrameDemo)
xOld = e.getX();
yOld = e.getY();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
//按住鼠标按键并移动鼠标时,记下鼠标坐标
int xOnScreen = e.getXOnScreen();//相对于屏幕的x坐标
int yOnScreen = e.getYOnScreen();//相对于屏幕的y坐标
int xNew = xOnScreen - xOld;
int yNew = yOnScreen - yOld;
JFrameDemo.this.setLocation(xNew, yNew);
}
});
/*
* JFrame增加背景图片
*/
ImageIcon background = new ImageIcon("image/Dog.png");// 背景图片图像图标
JLabel label = new JLabel(background);// 把背景图片显示在一个标签里面
//把标签的大小位置设置为图片刚好填充整个面板
label.setBounds(0, 0, background.getIconWidth(), background.getIconHeight());
//把内容窗格转化为JPanel,否则不能用方法setOpaque()来使内容窗格透明
imagePanel = (JPanel) this.getContentPane();
imagePanel.setOpaque(false);
//内容窗格默认的布局管理器为null
imagePanel.setLayout(null);
this.getLayeredPane().setLayout(null);
//把背景图片添加到分层窗格的最底层作为背景
this.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));
this.setUndecorated(true);// 去掉窗口的装饰
setSize(588, 588);
setLocationRelativeTo(null);// 窗口居中
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new JFrameDemo();
}
}
结构如下:
运行结果:
描述2:鼠标移动到组件(JButton、JPanel)上,改变样式(改变背景)。
我这次用的方法有点简单粗暴,但依然有效。图片采用png格式,因为png格式支持透明格式,然后把JButton的背景也设置为透明,同样,这种方法对JPanel也有效,这样你想要有什么形状的图片都可以了,但是需要指出的是,虽然是透明的,但是它的边角却是实实在在存在的。我这次样式的选择有反相、发光处理等,也可以在按钮不同状态设置按钮在不同的位置,来展现点击感。
填坑:为了按钮的实际范围仅在图片的非透明区域(不包括透明的边角),需要重写组件中的contains方法。
先看看自定义的JPanel和JButton效果。
package button;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* @Title: ButtonPanel.java
* @Package button
* @Description: 自定义的JPanel, 鼠标经过时更换背景图片,JPanel的形状取决于图片的形状
* @author Cqh_i
*/
public class ButtonPanel extends JPanel {
private static final long serialVersionUID = 1L;
private ImageIcon icon1;// 要变换的图片1
private ImageIcon icon2;// 要变换的图片2
// 下面的三个变量用于处理透明区域
private BufferedImage bi;
private int rgb, alpha;
private boolean isEntered = false; // 鼠标是否在组件里
private boolean isFirstCreated = true;// 是否是首次绘制的
public ButtonPanel(String path1, String path2) {
icon1 = new ImageIcon(path1);
icon2 = new ImageIcon(path2);
try {
bi = ImageIO.read(new File(path1));
} catch (IOException e) {
e.printStackTrace();
}
addListener();
setLayout(null);
setOpaque(false); // 把panel的背景色设为透明
}
@Override
public void paintComponent(Graphics g) {
int x = 0, y = 0;
// g.drawImage(icon.getImage(), x, y, getSize().width, getSize().height,
// this);// 图片会自动缩放
// g.drawImage(icon1.getImage(), x, y,this);//图片不会自动缩放
if (isFirstCreated) {
g.drawImage(icon1.getImage(), x, y, this);
isFirstCreated = false;
} else if (isEntered) {
g.drawImage(icon2.getImage(), x, y, this);
} else {
g.drawImage(icon1.getImage(), x, y, this);
}
}
/**
* 设置按钮点击范围仅在图片的非透明区域。
*/
@Override
public boolean contains(int x, int y) {
try {
rgb = bi.getRGB(x, y);
alpha = (rgb >> 24) & 0xFF;
if (alpha == 0) {
return false;
} else {
return true;
}
} catch (ArrayIndexOutOfBoundsException e) {
// 当搜索到透明区域时,就getRGB抛出下表越界异常
return false;
}
}
public void addListener() {
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JOptionPane.showMessageDialog(ButtonPanel.this, "你点击了自定义的JPanel!", "提示", JOptionPane.INFORMATION_MESSAGE);
}
@Override
public void mouseExited(MouseEvent e) {
isEntered = false;
repaint();
}
@Override
public void mouseEntered(MouseEvent e) {
isEntered = true;
repaint();
}
});
}
}
package button;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;
/**
* @Title: MyButton.java
* @Package button
* @Description: 自定义的JButton, 鼠标点击时改变图片的位置,JButton的形状取决于图片的形状
* @author Cqh_i
*/
public class MyButton extends JButton {
private static final long serialVersionUID = 1L;
private ImageIcon icon;// 背景图片
// 下面的三个变量用于处理透明区域
private BufferedImage bi;
private int rgb, alpha;
public MyButton(String path) {
this.icon = new ImageIcon(MyButton.class.getResource(path));
setContentAreaFilled(false);// 按钮设置为透明
setBorderPainted(false);// 去掉按钮的边框的设置
setSize(icon.getIconWidth(), icon.getIconHeight());
try {
bi = ImageIO.read(MyButton.class.getResource(path));
} catch (IOException e) {
e.printStackTrace();
}
addListener();
}
@Override
public void paintComponent(Graphics g) {
// 在按钮不同状态设置按钮在不同的位置,可以体现出点击感
if (this.getModel().isPressed()) {
g.drawImage(icon.getImage(), 2, 2, this);
} else {
g.drawImage(icon.getImage(), 0, 0, this);
}
}
/**
* 设置按钮点击范围仅在图片的非透明区域。
*/
@Override
public boolean contains(int x, int y) {
try {
rgb = bi.getRGB(x, y);
alpha = (rgb >> 24) & 0xFF;
if (alpha == 0) {
return false;
} else {
return true;
}
} catch (ArrayIndexOutOfBoundsException e) {
// 当搜索到透明区域时,就getRGB抛出下表越界异常
return false;
}
}
public void addListener() {
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseEntered(e);
JOptionPane.showMessageDialog(MyButton.this, "你点击了自定义的JButton!", "提示", JOptionPane.INFORMATION_MESSAGE);
}
});
}
}
package button;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
/**
* @Title: ButtonPanelDemo.java
* @Package test
* @Description: 测试自定义的JButton和自定义的JPanel
* @author Cqh_i
* @date 2018年10月31日22:23:05
*/
public class ButtonPanelDemo extends JFrame {
private static final long serialVersionUID = 1L;
public ButtonPanelDemo() {
JLabel Label1 = new JLabel("这是一个自定义的JButton");
Label1.setBounds(273, 13, 178, 18);
getContentPane().add(Label1);
/*
* 按钮JButton部分
*/
JButton ResetButton = new MyButton("WhiteBack.png");
ResetButton.setLocation(311, 32);
getContentPane().add(ResetButton);
/*
* JPanel部分
*/
ButtonPanel HomePanel = new ButtonPanel("WhiteBack.png","BlackArrowBack.png");
HomePanel.setBounds(67, 32, 114, 114);
getContentPane().add(HomePanel);
JLabel lblNewLabel = new JLabel("这是一个自定义的JPanel");
lblNewLabel.setBounds(37, 13, 175, 18);
getContentPane().add(lblNewLabel);
getContentPane().setLayout(null);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(500,300);
setLocationRelativeTo(null);// 窗口居中
setTitle("Demo make by Cqh_i");
}
public static void main(String[] args) {
new ButtonPanelDemo();
}
}
描述3:动态检测输入框的内容,给出相应信息,主要是实现在删除和添加字符时监听。
package test;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
/**
* @Title: ButtonPanelDemo.java
* @Package test
* @Description: 动态检测输入框的内容,给出相应信息。
* 这里以输入数字为有效字符,其他字符无效,19位号码为有效号码
* @author Cqh_i
*/
public class CheckTextDemo extends JFrame {
private static final long serialVersionUID = 1L;
private JTextField cardnumber_text;
private JLabel HintCardNumberInfo;
private boolean isCardNumberValid;// 卡号输入是否合法
public CheckTextDemo() {
HintCardNumberInfo = new JLabel();
HintCardNumberInfo.setForeground(Color.BLACK);
HintCardNumberInfo.setBounds(250, 70, 72, 18);
cardnumber_text = new JTextField();
cardnumber_text.setToolTipText("");
cardnumber_text.setFont(new Font("宋体", Font.BOLD, 18));
cardnumber_text.setBounds(41, 66, 206, 30);
cardnumber_text.setColumns(10);
/*
* 利用Document实现动态监听
*/
Document doc = cardnumber_text.getDocument();
doc.addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void insertUpdate(DocumentEvent e) {
if (cardnumber_text.isEditable() == true) {
try {
String str = doc.getText(0, doc.getLength());
isCardNumberValid = true;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) < '0' || str.charAt(i) > '9') {
HintCardNumberInfo.setText("无效的字符");
isCardNumberValid = false;
break;
}
if (isCardNumberValid && str.length() > 0 && str.length() < 19) {
isCardNumberValid = false;
HintCardNumberInfo.setText("小于19位");
}
if (isCardNumberValid && str.length() > 19) {
isCardNumberValid = false;
HintCardNumberInfo.setText("大于19位");
}
}
if (isCardNumberValid && str.length() == 19) {
HintCardNumberInfo.setText("");
}
if (str.length() == 0) {
HintCardNumberInfo.setText("");
}
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}
@Override
public void removeUpdate(DocumentEvent e) {
insertUpdate(e);
}
});
getContentPane().setLayout(null);
getContentPane().add(cardnumber_text);
getContentPane().add(HintCardNumberInfo);
JLabel lblNewLabel = new JLabel("请输入待检测内容");
lblNewLabel.setBounds(41, 35, 144, 18);
getContentPane().add(lblNewLabel);
setSize(400, 300);
setLocationRelativeTo(null);// 窗口居中
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("Demo make by Cqh_i");
}
public static void main(String[] args) {
new CheckTextDemo();
}
}
运行结果:
Java Swing中还有一个类JFormattedTextField,可以对输入文本框做出一些限制,有些轮子就不必重复造了,JFormattedTextField的使用见JFormattedTextField使用心得。