Java使用圖片自定義登錄窗體

一、問題概述

Java是一門面向對象的編程語言,從出版至今,Java對其自身不斷改進,Java的圖形界面編程也做的越來越好,從AWT到更高級的Swing。但是,我們的需求永遠是無法滿足的,有時候我們需要自定義窗體,特別是一張漂亮的圖片做一個窗體,那就再好不過了。那麼,今天我就把用圖片自定義應用窗體的方法分享給大家。

二、實現方法

1、用圖片自定義應用窗體效果圖;

Java使用圖片自定義應用窗體效果圖

                        圖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()) {
                //驗證用戶是否合法,合法打開主程序
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章