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()) {
                //验证用户是否合法,合法打开主程序
            }
        }
    }
}
  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
Java窗体组件的样式可以通过修改UI(User Interface)来自定义Java的Swing组件库提供了一种称为“可插拔外观(Pluggable Look and Feel)”的机制,使得可以在不修改应用程序代码的情况下,改变应用程序的外观和感觉。 可以通过编写自定义UI类来实现对Swing组件的自定义样式。例如,以下代码演示了如何创建一个自定义按钮UI,并将其应用于JButton组件: ```java import java.awt.*; import javax.swing.*; public class CustomButtonUI extends BasicButtonUI { // 重写绘制按钮的方法,实现自定义样式 @Override public void paint(Graphics g, JComponent c) { JButton button = (JButton) c; Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setColor(Color.BLUE); g2.fillRoundRect(0, 0, button.getWidth(), button.getHeight(), 10, 10); g2.setColor(Color.WHITE); g2.drawString(button.getText(), button.getWidth() / 2 - button.getFontMetrics(button.getFont()).stringWidth(button.getText()) / 2, button.getHeight() / 2 + button.getFontMetrics(button.getFont()).getHeight() / 3); } } // 创建一个自定义按钮 JButton button = new JButton("Click me!"); // 应用自定义UI button.setUI(new CustomButtonUI()); ``` 上述代码中,首先创建了一个自定义的按钮UI类CustomButtonUI,重写了paint方法,实现自定义样式。然后创建了一个JButton,将自定义UI应用于该按钮组件。 通过这种方式,可以对各种Swing组件进行自定义样式的设置,实现更加美观的界面效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值