Java使用圖片自定義登入窗體
一、問題概述
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()) {
//驗證使用者是否合法,合法開啟主程式
}
}
}
}