Java Swing: 令图像以等比例缩放或完全填充方式,自适应JLabel等组件大小

Java Swing:令图像以等比例缩放或完全填充方式,自适应JLabel、JButton等组件大小


向如下工具类中的方法传入图像信息,来获得一个 Icon对象。此 Icon对象能够自适应 JLabelJButton大小进行缩放。

代码中的方法为静态方法,可直接使用。后续 Demo注释 部分对代码内容和设计思路进行了详细介绍,希望能为大家提供一些参考,可略过。

代码

import java.net.URL;
import java.awt.Point;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Dimension;
import javax.swing.ImageIcon;

/**Title: SwingUtil.java
 * Swing工具类
 * 
 * @author Run
 * @date  2019-08-20 */
public class SwingUtil {
        
    /**创建一个可以自适应组件大小的ImageIcon对象
     * @param image 从<code> Image </code>对象来创建ImageIcon
     * @param constrained 是否等比例缩放 。当为<code> true </code>时,可通过
     *      {@link javax.swing.JComponent#setAlignmentX(float)}和
     *      {@link javax.swing.JComponent#setAlignmentY(float)}方法设置组件对齐方式。
     * @date  2019-08-20 */
    public static ImageIcon createAutoAdjustIcon(Image image, boolean constrained) {
        ImageIcon icon = new ImageIcon(image) {
            @Override
            public synchronized void paintIcon(java.awt.Component cmp, Graphics g, int x, int y) {
                //初始化参数
                Point startPoint = new Point(0, 0);//默认绘制起点
                Dimension cmpSize = cmp.getSize();//获取组件大小
                Dimension imgSize = new Dimension(getIconWidth(), getIconHeight());//获取图像大小
                
                //计算绘制起点和区域
                if(constrained) {//等比例缩放
                    //计算图像宽高比例
                    double ratio = 1.0*imgSize.width/imgSize.height;
                    //计算等比例缩放后的区域大小
                    imgSize.width = (int) Math.min(cmpSize.width, ratio*cmpSize.height);
                    imgSize.height = (int) (imgSize.width/ratio);
                    //计算绘制起点
                    startPoint.x = (int) 
                            (cmp.getAlignmentX()*(cmpSize.width - imgSize.width));
                    startPoint.y = (int) 
                            (cmp.getAlignmentY()*(cmpSize.height - imgSize.height));
                } else {//完全填充
                    imgSize = cmpSize;
                }
                
                //根据起点和区域大小进行绘制
                if(getImageObserver() == null) {
                    g.drawImage(getImage(), startPoint.x, startPoint.y,
                            imgSize.width, imgSize.height, cmp);
                 } else {
                    g.drawImage(getImage(), startPoint.x, startPoint.y,
                            imgSize.width, imgSize.height, getImageObserver());
                 }
            };
        };
        return icon;
    }
    
    /**创建一个可以自适应组件大小的Icon对象
     * @param filename 指定文件名或者路径的字符串
     * @param constrained 是否等比例缩放。当为<code> true </code>时,可通过
     *      {@link javax.swing.JComponent#setAlignmentX(float)}和
     *      {@link javax.swing.JComponent#setAlignmentY(float)}方法设置组件对齐方式。
     * @date  2019-08-20 */
    public static ImageIcon createAutoAdjustIcon(String filename, boolean constrained) {
        return createAutoAdjustIcon(new ImageIcon(filename).getImage(), constrained);
    }
    
    /**创建一个可以自适应组件大小的ImageIcon对象
     * @param url 从指定的<code> URL </code>对象来创建ImageIcon
     * @param constrained 是否等比例缩放 。当为<code> true </code>时,可通过
     *      {@link javax.swing.JComponent#setAlignmentX(float)}和
     *      {@link javax.swing.JComponent#setAlignmentY(float)}方法设置组件对齐方式。
     * @date  2019-08-20 */
    public static ImageIcon createAutoAdjustIcon(URL url, boolean constrained) {
        return createAutoAdjustIcon(new ImageIcon(url).getImage(), constrained);
    }
    
}

使用:

  1. 通过代码中SwingUtil.createAutoAdjustIcon(String , boolean)等静态方法,创建一个能自适应组件大小的ImageIcon对象。
  2. 在实现了setIcon(Icon)方法的JComponent组件(如JLabelJButton)中,调用setIcon(Icon)方法,设置组件图标为该ImageIcon

注意:

  1. 在组件(如JLabel)中最好只放置此Icon,不添加其它图标或文本,否则这些内容之间会产生覆盖。
  2. 当图像属性设置为等比例缩放时,可以调用JComponentsetAlignmentX(float)setAlignmentY(float)方法,分别设置图标的水平或垂直对齐方式。

Demo

下面的Demo展示了一张网络图片在JLabel里的三种适应样式(等比例缩放、完全填充、不缩放)。

package demo;

import java.net.URL;
import java.awt.Point;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Dimension;
import javax.swing.ImageIcon;

import javax.swing.JLabel;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import javax.swing.border.LineBorder;
import java.net.MalformedURLException;

/**Title: Demo.java
 * 示例代码
 * 
 * @author Run
 * @date  2019-08-20 */
public class Demo{

    public static void main(String args[]){
        SwingUtilities.invokeLater( () ->{
            //运行示例代码
            AutoAdjustIconDemo();
        });
    }
    
    /**图像自适应组件大小
     * @date  2019-08-20 */
    static void AutoAdjustIconDemo() {
        JFrame frame=new JFrame("Auto-adjust Icon");
        JPanel panel=new JPanel(new GridLayout(1, 3, 10, 10));
        //导入图片
        Image image = null;
        try {
            //一张来自CSDN的默认用户头像
            URL url = new URL("https://imgconvert.csdnimg.cn/"
                    + "aHR0cHM6Ly9hdmF0YXIuY3Nkbi5uZXQvNy83L0IvMV9yYWxmX2h4MTYzY29tLmpwZw");
            image = new ImageIcon(url).getImage();
        } catch (MalformedURLException e) {
            System.out.println("HTTP ERROR 404");
        }
        //等比例JLabel
        JLabel ratioLabel = new JLabel();
        ratioLabel.setIcon(SwingUtil.createAutoAdjustIcon(image, true));
        ratioLabel.setBorder(new LineBorder(Color.RED));
        ratioLabel.setAlignmentX(0.5F);
        ratioLabel.setAlignmentY(0.5F);
        //不等比例JLabel
        JLabel filledLabel = new JLabel();
        filledLabel.setIcon(SwingUtil.createAutoAdjustIcon(image, false));
        filledLabel.setBorder(new LineBorder(Color.ORANGE));
        //常规样式JLabel
        JLabel normalLabel = new JLabel();
        normalLabel.setIcon(new ImageIcon(image));
        normalLabel.setBorder(new LineBorder(Color.BLUE));
        //JPanel内容
        panel.add(ratioLabel);
        panel.add(filledLabel);
        panel.add(normalLabel);
        //JFrame内容
        frame.getContentPane().add(panel);
        frame.setSize(600,480);
        //JFrame属性
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

//
/**Swing工具类
 * 
 * @author Run
 * @date  2019-08-20 */
class SwingUtil {

    /**创建一个可以自适应组件大小的ImageIcon对象
     * @param image 从<code> Image </code>对象来创建ImageIcon
     * @param constrained 是否等比例缩放 。当为<code> true </code>时,可通过
     *      {@link javax.swing.JComponent#setAlignmentX(float)}和
     *      {@link javax.swing.JComponent#setAlignmentY(float)}方法设置组件对齐方式。
     * @date  2019-08-20 */
    public static ImageIcon createAutoAdjustIcon(Image image, boolean constrained) {
        ImageIcon icon = new ImageIcon(image) {
            @Override
            public synchronized void paintIcon(java.awt.Component cmp, Graphics g, int x, int y) {
                //初始化参数
                Point startPoint = new Point(0, 0);//默认绘制起点
                Dimension cmpSize = cmp.getSize();//获取组件大小
                Dimension imgSize = new Dimension(getIconWidth(), getIconHeight());//获取图像大小
                
                //计算绘制起点和区域
                if(constrained) {//等比例缩放
                    //计算图像宽高比例
                    double ratio = 1.0*imgSize.width/imgSize.height;
                    //计算等比例缩放后的区域大小
                    imgSize.width = (int) Math.min(cmpSize.width, ratio*cmpSize.height);
                    imgSize.height = (int) (imgSize.width/ratio);
                    //计算绘制起点
                    startPoint.x = (int) 
                            (cmp.getAlignmentX()*(cmpSize.width - imgSize.width));
                    startPoint.y = (int) 
                            (cmp.getAlignmentY()*(cmpSize.height - imgSize.height));
                } else {//完全填充
                    imgSize = cmpSize;
                }
                
                //根据起点和区域大小进行绘制
                if(getImageObserver() == null) {
                    g.drawImage(getImage(), startPoint.x, startPoint.y,
                            imgSize.width, imgSize.height, cmp);
                 } else {
                    g.drawImage(getImage(), startPoint.x, startPoint.y,
                            imgSize.width, imgSize.height, getImageObserver());
                 }
            };
        };
        return icon;
    }
    
    /**创建一个可以自适应组件大小的Icon对象
     * @param filename 指定文件名或者路径的字符串
     * @param constrained 是否等比例缩放。当为<code> true </code>时,可通过
     *      {@link javax.swing.JComponent#setAlignmentX(float)}和
     *      {@link javax.swing.JComponent#setAlignmentY(float)}方法设置组件对齐方式。
     * @date  2019-08-20 */
    public static ImageIcon createAutoAdjustIcon(String filename, boolean constrained) {
        return createAutoAdjustIcon(new ImageIcon(filename).getImage(), constrained);
    }
    
    /**创建一个可以自适应组件大小的ImageIcon对象
     * @param url 从指定的<code> URL </code>对象来创建ImageIcon
     * @param constrained 是否等比例缩放 。当为<code> true </code>时,可通过
     *      {@link javax.swing.JComponent#setAlignmentX(float)}和
     *      {@link javax.swing.JComponent#setAlignmentY(float)}方法设置组件对齐方式。
     * @date  2019-08-20 */
    public static ImageIcon createAutoAdjustIcon(URL url, boolean constrained) {
        return createAutoAdjustIcon(new ImageIcon(url).getImage(), constrained);
    }
    
}

运行结果:
运行结果

注释

在Java Swing中,部分JComponent组件实现了setIcon(Icon)方法,如JLabelJButton等。通过setIcon(Icon)可以在组件中设置需要显示的图像。其中的Icon接口有三个方法:

public interface Icon
{
	/**
     * Draw the icon at the specified location.  Icon implementations
     * may use the Component argument to get properties useful for
     * painting, e.g. the foreground or background color.
     */
    void paintIcon(Component c, Graphics g, int x, int y);
    
    int getIconWidth();
    int getIconHeight();
}

ImageIcon类实现了Icon接口。上面程序中的关键代码SwingUtil.createAutoAdjustIcon(String , boolean),便是通过覆盖ImageIcon里的paintIcon(Component, Graphics, int, int)方法,来实现图像的缩放功能。

Swing 使用的是 MVC 框架。组件模型会在程序在运行时,委托对应的UI对象进行内容绘制。所以,在JLabel对应的基本UI类javax.swing.plaf.basic.BasicLabelUI中,可以寻找到对应的图像显示代码。在其BasicLabelUI.paint(Graphics, javax.swing.JComponent)方法中,可以看到:
BasicLabelUI.paint(Graphics, javax.swing.JComponent)
由此看出,JLabel中图像的绘制任务,最终转交给了Icon类的paintIcon(Component, Graphics, int, int)方法这里。

接下来的事情就简单了。在paintIcon(Component, Graphics, int, int)方法中,通过传入参数,可以获得:当前正在进行绘制的组件、图形上下文和图像左上角顶点。如果图像仅需要完全填充的样式,可以省略计算等比例缩放的过程,直接按照下面这样写:

	public synchronized void paintIcon(java.awt.Component cmp, Graphics g, int x, int y) {
		g.drawImage(getImage(), 0, 0, cmp.getWidth(), cmp.getHeight(), cmp);
	}

java.awt.Graphics.drawImage(Image, int, int, int, int, ImageObserver)方法会自动将图像(Image参数)缩放到需要绘制的区域中。

当等比例缩放图片时,需要在调用drawImage(Image, int, int, int, int, ImageObserver)方法前,额外进行一些计算:

  1. 计算图像宽和高的像素比;
  2. 依据图像像素比和组件的宽、高,计算组件能支持的最大图像尺寸;
  3. 计算缩放后,图像宽高与组件宽高间的差值,并依据组件X轴、Y轴的对齐参数,求出图像左上角顶点的坐标;
  4. 依据图像缩放后左上角顶点的坐标、缩放后的尺寸,对图像进行绘制。

即:

				/* cmp 为需要进行绘制的 Component 组件 */
				//初始化参数
                Point startPoint = new Point(0, 0);//默认绘制起点
                Dimension cmpSize = cmp.getSize();//获取组件大小
                Dimension imgSize = new Dimension(getIconWidth(), getIconHeight());//获取图像大小
                
                /* 等比例缩放,需要计算绘制起点和区域 */
                //计算图像宽高比例
                double ratio = 1.0*imgSize.width/imgSize.height;
                //计算等比例缩放后的区域大小
                imgSize.width = (int) Math.min(cmpSize.width, ratio*cmpSize.height);
                imgSize.height = (int) (imgSize.width/ratio);
                //计算绘制起点
                startPoint.x = (int) 
                        (cmp.getAlignmentX()*(cmpSize.width - imgSize.width));
                startPoint.y = (int) 
                        (cmp.getAlignmentY()*(cmpSize.height - imgSize.height));

两种缩放方式整合在一起,并结合ImageIcon类的几个常用接口,便实现了文章开头部分的代码。

  • 17
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Java Swing中,可以使用JLabel来显示背景图像,并使用ImageIcon来加载图像。要实现等比例缩放完全填充方式,可以通过计算图像组件大小比例来进行缩放。以下是一个示例代码: ```java import java.awt.*; import javax.swing.*; public class BackgroundImage extends JFrame { private JLabel backgroundImageLabel; private ImageIcon backgroundImage; public BackgroundImage() { initComponents(); } private void initComponents() { setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setPreferredSize(new Dimension(600, 400)); // 加载背景图像 backgroundImage = new ImageIcon(getClass().getResource("/path/to/image.jpg")); // 创建JLabel并设置布局 backgroundImageLabel = new JLabel(); backgroundImageLabel.setLayout(new BorderLayout()); setContentPane(backgroundImageLabel); // 添加背景图像JLabel setBackgroundImage(backgroundImageLabel, backgroundImage); pack(); } /** * 设置背景图像 * @param label 背景图像要添加到的JLabel * @param image 要设置的背景图像 */ private void setBackgroundImage(JLabel label, ImageIcon image) { Image i = image.getImage(); int labelWidth = label.getWidth(); int labelHeight = label.getHeight(); int imageWidth = i.getWidth(null); int imageHeight = i.getHeight(null); // 计算图像组件大小比例 double widthRatio = (double) labelWidth / imageWidth; double heightRatio = (double) labelHeight / imageHeight; if (widthRatio > heightRatio) { // 如果宽度比例较大,按比例缩放图像宽度 int newWidth = (int) (imageWidth * heightRatio); Image newImage = i.getScaledInstance(newWidth, labelHeight, Image.SCALE_SMOOTH); label.setIcon(new ImageIcon(newImage)); } else { // 如果高度比例较大,按比例缩放图像高度 int newHeight = (int) (imageHeight * widthRatio); Image newImage = i.getScaledInstance(labelWidth, newHeight, Image.SCALE_SMOOTH); label.setIcon(new ImageIcon(newImage)); } } public static void main(String[] args) { SwingUtilities.invokeLater(() -> new BackgroundImage().setVisible(true)); } } ``` 上述代码中,创建了一个JLabel作为背景,并将背景图像添加到其中。在`setBackgroundImage()`方法中,根据组件图像大小比例来进行图像缩放。如果宽度比例较大,则按比例缩放图像宽度使其填充整个组件宽度;如果高度比例较大,则按比例缩放图像高度使其填充整个组件高度。最终将缩放后的图像添加到JLabel中,作为背景图像

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值