您的位置:首页 > 编程语言 > Java开发

Java使用图片自定义登录窗体

2016-06-03 10:49 435 查看
一、问题概述

Java是一门面向对象的编程语言,从出版至今,Java对其自身不断改进,Java的图形界面编程也做的越来越好,从AWT到更高级的Swing。但是,我们的需求永远是无法满足的,有时候我们需要自定义窗体,特别是一张漂亮的图片做一个窗体,那就再好不过了。那么,今天我就把用图片自定义应用窗体的方法分享给大家。

二、实现方法

1、用图片自定义应用窗体效果图;



图1 Java使用图片自定义应用窗体效果图


2、创建一个类继承Swing中JFrame,然后定义一个BufferedImage变量,用于设定应用窗体背景图,在定义一个ImageIcon变量,用来保存你自定义的图片;在根据图1的样子,分别定义两个JLable,一个JTextField,一个JPasswordField,三个JButton。图片的导入和组件的创建不在鳌诉。

说明:图1右上角的红色关闭窗体按钮是自定义图片p上去的,然后通过Java的鼠标事件来判断鼠标点击的范围是否在红色区域内,如果觉得上诉的按钮或者是文本框不好看,也可以用自定义的图片去定义样式,此内容不再本教程讲解范围之类,具体方法请参阅我博客“Java自定义图片按钮”。

下面给出变量代码:

// 用来设定窗体不规则样式的图片,这里只用它来创建窗体形状
private BufferedImage img;
//用它来显示这张图片
private ImageIcon background;
//用户名输入框
private JTextField userText = new JTextField(30);
//密码输入框
private JPasswordField passwordText = new JPasswordField(30);
private JLabel userLabel = new JLabel("账 号:");
private JLabel passwordLabel = new JLabel("密 码: ");
private JButton okbtn = new JButton("确定");
private JButton resert = new JButton("重置");
private JButton register = new JButton("注册");
// 记录窗体移动的坐标
private Point origin;


如果不使用JLable 来显示background图片,效果是这样的:



图2 未设置背景图像效果图


为方便测试,再此给出图片原图(P得不是很好,P得越清晰,就越不容易产生锯齿和白边哦):



图3 应用原图


3、创建一个和图片形状一样的窗体;

/**
* 创建和图片形状一样的窗体
* 并监听窗体移动事件
* @throws IOException
*/
private void initialize() throws IOException { // 窗体初始化
// 设定窗体大小和图片一样大
this.setSize(img.getWidth(null), img.getHeight(null));
// 设定禁用窗体装饰,这样就取消了默认的窗体结构
this.setUndecorated(true);
// 初始化用于移动窗体的原点
this.origin = new Point();

// 调用AWTUtilities的setWindowShape方法设定本窗体为制定的Shape形状
AWTUtilities.setWindowShape(this, getImageShape(img));
// 设定窗体可见度
AWTUtilities.setWindowOpacity(this, 0.8f);

this.setLocationRelativeTo(null);
this.setAlwaysOnTop(true);
// 由于取消了默认的窗体结构,所以我们要手动设置一下移动窗体的方法
this.addMouseListener(new OwnListener());
//监听鼠标移动事件
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
Point p = getLocation();
setLocation(p.x + e.getX() - origin.x, p.y + e.getY()
- origin.y);
}
});
}
/**
* 将Image图像转换为Shape图形
* @param img
* @return
*/
public Shape getImageShape(Image img) {
ArrayList<Integer> x = new ArrayList<Integer>();
ArrayList<Integer> y = new ArrayList<Integer>();
int width = img.getWidth(null);// 图像宽度
int height = img.getHeight(null);// 图像高度

// 筛选像素
// 首先获取图像所有的像素信息
PixelGrabber pgr = new PixelGrabber(img, 0, 0, -1, -1, true);
try {
pgr.grabPixels();
} catch (InterruptedException ex) {
ex.getStackTrace();
}
int pixels[] = (int[]) pgr.getPixels();

// 循环像素
for (int i = 0; i < pixels.length; i++) {
// 筛选,将不透明的像素的坐标加入到坐标ArrayList x和y中
int alpha = getAlpha(pixels[i]);
if (alpha == 0) {
continue;
} else {
x.add(i % width > 0 ? i % width - 1 : 0);
y.add(i % width == 0 ? (i == 0 ? 0 : i / width - 1) : i / width);
}
}

// 建立图像矩阵并初始化(0为透明,1为不透明)
int[][] matrix = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
matrix[i][j] = 0;
}
}

// 导入坐标ArrayList中的不透明坐标信息
for (int c = 0; c < x.size(); c++) {
matrix[y.get(c)][x.get(c)] = 1;
}

/*
* 由于Area类所表示区域可以进行合并,我们逐一水平"扫描"图像矩阵的每一行,
* 将不透明的像素生成为Rectangle,再将每一行的Rectangle通过Area类的rec
* 对象进行合并,最后形成一个完整的Shape图形
*/
Area rec = new Area();
int temp = 0;

for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (matrix[i][j] == 1) {
if (temp == 0)
temp = j;
else if (j == width) {
if (temp == 0) {
Rectangle rectemp = new Rectangle(j, i, 1, 1);
rec.add(new Area(rectemp));
} else {
Rectangle rectemp = new Rectangle(temp, i,
j - temp, 1);
rec.add(new Area(rectemp));
temp = 0;
}
}
} else {
if (temp != 0) {
Rectangle rectemp = new Rectangle(temp, i, j - temp, 1);
rec.add(new Area(rectemp));
temp = 0;
}
}
}
temp = 0;
}
return rec;
}

/**
* 取得透明度
* @param pixel
* @return
*/
private int getAlpha(int pixel) {
return (pixel >> 24) & 0xff;
}


4、初始化窗体并显示

/**
* 构造方法
* 初始化窗体
*/
public LoginWindow() {
super();

sql = new DriveSQL();

background = new ImageIcon("image1\\login1.png");
JLabel back = new JLabel(background);
back.setBounds(0, 0, background.getIconWidth(),
background.getIconHeight());
/*
* 首先初始化一张图片,我们可以选择一张有透明部分的不规则图片
*  (要想图片能够显示透明,必须使用PNG格式的图片)
*/
MediaTracker mt = new MediaTracker(this);

try {
img = ImageIO.read(new File("image1\\login1.png"));
} catch (IOException e1) {
e1.printStackTrace();
}

mt.addImage(img, 0);

try {
mt.waitForAll(); // 开始加载由此媒体跟踪器跟踪的所有图像
} catch (InterruptedException e) {
e.printStackTrace();
}

try {
initialize(); // 窗体形状初始化
} catch (IOException e) {
e.printStackTrace();
}

addMenu();
this.add(back);
this.setVisible(true);
}
/**
* 组件初始化
*/
public void addMenu() {
//采用绝对布局,要将默认布局置空
this.setLayout(null);
//设置字体
Font font = new Font("", 0, 18);
userLabel.setForeground(Color.white);
passwordLabel.setForeground(Color.white);
userLabel.setFont(font);
passwordLabel.setFont(font);
passwordText.setEchoChar('*');

userLabel.setBounds(80, 120, 100, 50);
passwordLabel.setBounds(80, 160, 100, 50);
userText.setBounds(140, 130, 170, 30);
passwordText.setBounds(140, 170, 170, 30);
okbtn.setBounds(81, 210, 60, 25);
resert.setBounds(166, 210, 60, 25);
register.setBounds(251, 210, 60, 25);

this.add(userLabel);
this.add(userText);
this.add(passwordLabel);
this.add(passwordText);
this.add(okbtn);
this.add(resert);
this.add(register);

okbtn.addMouseListener(new OwnListener());
resert.addMouseListener(new OwnListener());
register.addMouseListener(new OwnListener());
userText.addKeyListener(new KeyOwnListener());
passwordText.addKeyListener(new KeyOwnListener());
}


5、事件响应

/**
* 事件监听
* @author Admin
*
*/
private class OwnListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
origin.x = e.getX();
origin.y = e.getY();
}

// 窗体上单击鼠标右键关闭程序
public void mouseClicked(MouseEvent e) {
//如果点击的区域位于右上角红色按钮,则关闭程序
if (new Circle(350, 63, 11).contants(e.getX(), e.getY())) {
System.exit(0);
} else if (e.getSource() == okbtn) {
//验证用户是否合法,并打开主程序
} else if (e.getSource() == resert) {
userText.setText("");
passwordText.setText("");
} else if (e.getSource() == register) {
//打开注册页面
}
}

public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
}
}


三、小结

1、要实现自定义图片创建窗体,必须使用Java的第三方库的类“AWTUtilities”,如果你在使用时发现找不到此类,原因可能是你的JDK版本过低或者是你配置时没有导入第三方库。如无法解决,请联系我。

2、创建窗体时,采用绝对布局,要将原有的默认布局置空,否则很难控制。具体原因可以自己去尝试。

3、如果要实现窗体透明,图片必须使用png格式,小编曾经就是实现不了透明效果头疼了很久,最后发现只有png格式的图片可以实现透明效果。

4、部分源码参考网络和前辈博客,感谢提供相应资料。

5、由于小编初出茅庐,文中难免有错误之处,还望指正,谢谢合作。

四、完整源码

import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

import com.assistclass.Circle;
import com.data.Reader;
import com.frame.MainFrame;
import com.sqlservice.DriveSQL;
import com.sun.awt.AWTUtilities;

/**
* 用户登录窗体
* @author Admin
*
*/
public class LoginWindow extends JFrame {

private static final long serialVersionUID = 1L;
private Point origin; // 用于移动窗体
private BufferedImage img; // 用来设定窗体不规则样式的图片

private ImageIcon background;
private JTextField userText = new JTextField(30);
private JPasswordField passwordText = new JPasswordField(30);
private JLabel userLabel = new JLabel("账 号:");
private JLabel passwordLabel = new JLabel("密 码: ");
private JButton okbtn = new JButton("确定");
private JButton resert = new JButton("重置");
private JButton register = new JButton("注册");

/**
* 初始化窗体
*/
public LoginWindow() {
super();
background = new ImageIcon("image1\\login1.png");
JLabel back = new JLabel(background);
back.setBounds(0, 0, background.getIconWidth(),
background.getIconHeight());
/*
* 首先初始化一张图片,我们可以选择一张有透明部分的不规则图片
*  (要想图片能够显示透明,必须使用PNG格式的图片)
*/
MediaTracker mt = new MediaTracker(this);

try {
img = ImageIO.read(new File("image1\\login1.png"));
} catch (IOException e1) {
e1.printStackTrace();
}

mt.addImage(img, 0);

try {
mt.waitForAll(); // 开始加载由此媒体跟踪器跟踪的所有图像
} catch (InterruptedException e) {
e.printStackTrace();
}

try {
initialize(); // 窗体形状初始化
} catch (IOException e) {
e.printStackTrace();
}

addMenu();
this.add(back);
this.setVisible(true);
}

/**
* 组件初始化
*/
public void addMenu() {
this.setLayout(null);
//设置字体
Font font = new Font("", 0, 18);
userLabel.setForeground(Color.white);
passwordLabel.setForeground(Color.white);
userLabel.setFont(font);
passwordLabel.setFont(font);
passwordText.setEchoChar('*');

userLabel.setBounds(80, 120, 100, 50);
passwordLabel.setBounds(80, 160, 100, 50);
userText.setBounds(140, 130, 170, 30);
passwordText.setBounds(140, 170, 170, 30);
okbtn.setBounds(81, 210, 60, 25);
resert.setBounds(166, 210, 60, 25);
register.setBounds(251, 210, 60, 25);

this.add(userLabel);
this.add(userText);
this.add(passwordLabel);
this.add(passwordText);
this.add(okbtn);
this.add(resert);
this.add(register);

okbtn.addMouseListener(new OwnListener());
resert.addMouseListener(new OwnListener());
register.addMouseListener(new OwnListener());
userText.addKeyListener(new KeyOwnListener());
passwordText.addKeyListener(new KeyOwnListener());

userText.setText("20160601");
passwordText.setText("84878323");
}

/**
* 创建和图片形状一样的窗体
* @throws IOException
*/
private void initialize() throws IOException { // 窗体初始化
// 设定窗体大小和图片一样大
this.setSize(img.getWidth(null), img.getHeight(null));
// 设定禁用窗体装饰,这样就取消了默认的窗体结构
this.setUndecorated(true);
// 初始化用于移动窗体的原点
this.origin = new Point();

// 调用AWTUtilities的setWindowShape方法设定本窗体为制定的Shape形状
AWTUtilities.setWindowShape(this, getImageShape(img));
// 设定窗体可见度
AWTUtilities.setWindowOpacity(this, 0.8f);

this.setLocationRelativeTo(null);
this.setAlwaysOnTop(true);
// 由于取消了默认的窗体结构,所以我们要手动设置一下移动窗体的方法
this.addMouseListener(new OwnListener());
//监听鼠标移动事件
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
Point p = getLocation();
setLocation(p.x + e.getX() - origin.x, p.y + e.getY()
- origin.y);
}
});
}

/**
* 将Image图像转换为Shape图形
* @param img
* @return
*/
public Shape getImageShape(Image img) {
ArrayList<Integer> x = new ArrayList<Integer>();
ArrayList<Integer> y = new ArrayList<Integer>();
int width = img.getWidth(null);// 图像宽度
int height = img.getHeight(null);// 图像高度

// 筛选像素
// 首先获取图像所有的像素信息
PixelGrabber pgr = new PixelGrabber(img, 0, 0, -1, -1, true);
try {
pgr.grabPixels();
} catch (InterruptedException ex) {
ex.getStackTrace();
}
int pixels[] = (int[]) pgr.getPixels();

// 循环像素
for (int i = 0; i < pixels.length; i++) {
// 筛选,将不透明的像素的坐标加入到坐标ArrayList x和y中
int alpha = getAlpha(pixels[i]);
if (alpha == 0) {
continue;
} else {
x.add(i % width > 0 ? i % width - 1 : 0);
y.add(i % width == 0 ? (i == 0 ? 0 : i / width - 1) : i / width);
}
}

// 建立图像矩阵并初始化(0为透明,1为不透明)
int[][] matrix = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
matrix[i][j] = 0;
}
}

// 导入坐标ArrayList中的不透明坐标信息
for (int c = 0; c < x.size(); c++) {
matrix[y.get(c)][x.get(c)] = 1;
}

/*
* 由于Area类所表示区域可以进行合并,我们逐一水平"扫描"图像矩阵的每一行,
* 将不透明的像素生成为Rectangle,再将每一行的Rectangle通过Area类的rec
* 对象进行合并,最后形成一个完整的Shape图形
*/
Area rec = new Area();
int temp = 0;

for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (matrix[i][j] == 1) {
if (temp == 0)
temp = j;
else if (j == width) {
if (temp == 0) {
Rectangle rectemp = new Rectangle(j, i, 1, 1);
rec.add(new Area(rectemp));
} else {
Rectangle rectemp = new Rectangle(temp, i,
j - temp, 1);
rec.add(new Area(rectemp));
temp = 0;
}
}
} else {
if (temp != 0) {
Rectangle rectemp = new Rectangle(temp, i, j - temp, 1);
rec.add(new Area(rectemp));
temp = 0;
}
}
}
temp = 0;
}
return rec;
}

/**
* 取得透明度
* @param pixel
* @return
*/
private int getAlpha(int pixel) {
return (pixel >> 24) & 0xff;
}

/**
* 事件监听
* @author Admin
*
*/
private class OwnListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
origin.x = e.getX();
origin.y = e.getY();
}

// 窗体上单击鼠标右键关闭程序
public void mouseClicked(MouseEvent e) {
//如果点击的区域位于右上角红色按钮,则关闭程序
if (new Circle(350, 63, 11).contants(e.getX(), e.getY())) {
System.exit(0);
} else if (e.getSource() == okbtn) {
//验证用户是否合法,合法打开主程序
} else if (e.getSource() == resert) {
userText.setText("");
passwordText.setText("");
} else if (e.getSource() == register) {
//打开注册页面
}
}

public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
}
}

/**
* 监听键盘Enter键,实现Enter登录
* @author Admin
*
*/
private class KeyOwnListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (10 == e.getKeyCode()) {
//验证用户是否合法,合法打开主程序
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  自定义窗体