You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

幻灯片程序中,如何让ImageIcon在JFrame实时缩放适配窗口?

实现图片实时缩放适配窗口的幻灯片程序

当然可以实现窗口拉伸时图片实时缩放的效果!你当前的代码直接用JLabel加载ImageIcon的方式没办法自动响应窗口尺寸变化,我们需要自定义一个绘制组件,在窗口大小改变时重新缩放并绘制图片。

核心思路

  1. 自定义绘制组件:继承JPanel,重写paintComponent方法,在绘制时将图片缩放至组件的当前尺寸(无需保持比例)。
  2. 监听窗口尺寸变化:给窗口添加ComponentListener,当窗口大小改变时触发组件重绘,重新计算图片缩放尺寸。
  3. 优化幻灯片切换逻辑:原代码用Thread.sleep会阻塞Swing的事件调度线程(EDT),导致界面卡顿,改用Swing Timer来实现定时切换,更符合Swing的线程规范。

修改后的完整代码

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class SlideshowApp {
    private JFrame frame;
    private ImagePanel imagePanel;
    private List<Image> imageList;
    private List<String> nonImageMessages;
    private int currentIndex = 0;
    private Timer slideTimer;
    private long slideDuration;
    private int messageFontSize;

    public SlideshowApp(String path, long duration, int fontSize) {
        slideDuration = duration;
        messageFontSize = fontSize;
        imageList = new ArrayList<>();
        nonImageMessages = new ArrayList<>();
        loadMedia(path);

        // 初始化主窗口
        frame = new JFrame("Slideshow");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH); // 初始最大化,也可以自定义大小

        // 初始化自定义图片面板
        imagePanel = new ImagePanel();
        frame.add(imagePanel);

        // 监听窗口大小变化,触发重绘
        frame.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                imagePanel.repaint();
            }
        });

        // 初始化切换定时器
        slideTimer = new Timer((int) slideDuration, e -> showNextSlide());
        slideTimer.setInitialDelay(0);
    }

    // 加载指定路径下的图片和非图片文件
    private void loadMedia(String path) {
        File target = new File(path);
        if (target.isDirectory()) {
            File[] files = target.listFiles();
            if (files != null) {
                for (File file : files) {
                    try {
                        Image image = ImageIO.read(file);
                        if (image != null) {
                            imageList.add(image);
                        } else {
                            nonImageMessages.add("Not an image: " + file.getName());
                        }
                    } catch (IOException ex) {
                        nonImageMessages.add("Failed to load: " + file.getName());
                    }
                }
            }
        } else {
            try {
                Image image = ImageIO.read(target);
                if (image != null) {
                    imageList.add(image);
                } else {
                    nonImageMessages.add("Target is not an image");
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                nonImageMessages.add("Failed to load target file");
            }
        }
        // 添加结束提示
        nonImageMessages.add("End of presentation");
    }

    // 切换到下一张幻灯片
    private void showNextSlide() {
        if (currentIndex < imageList.size()) {
            imagePanel.setImage(imageList.get(currentIndex));
            imagePanel.setMessage(null);
        } else if (currentIndex < imageList.size() + nonImageMessages.size()) {
            imagePanel.setImage(null);
            imagePanel.setMessage(nonImageMessages.get(currentIndex - imageList.size()));
        } else {
            slideTimer.stop();
            frame.dispose();
            return;
        }
        currentIndex++;
        imagePanel.repaint();
    }

    // 启动幻灯片
    public void start() {
        frame.setVisible(true);
        if (!imageList.isEmpty() || !nonImageMessages.isEmpty()) {
            slideTimer.start();
        }
    }

    // 自定义面板,负责绘制缩放后的图片或文本
    private class ImagePanel extends JPanel {
        private Image currentImage;
        private String currentMessage;

        public void setImage(Image image) {
            currentImage = image;
        }

        public void setMessage(String message) {
            currentMessage = message;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

            if (currentImage != null) {
                // 将图片缩放至面板的当前尺寸
                g2d.drawImage(currentImage, 0, 0, getWidth(), getHeight(), this);
            } else if (currentMessage != null) {
                // 绘制居中的提示文本
                Font font = new Font("Serif", Font.PLAIN, messageFontSize);
                g2d.setFont(font);
                FontMetrics metrics = g2d.getFontMetrics(font);
                int x = (getWidth() - metrics.stringWidth(currentMessage)) / 2;
                int y = (getHeight() - metrics.getHeight()) / 2 + metrics.getAscent();
                g2d.drawString(currentMessage, x, y);
            }
        }
    }

    public static void main(String[] args) {
        if (args.length < 3) {
            System.out.println("Usage: java SlideshowApp <image path> <slide duration (ms)> <message font size>");
            return;
        }
        String path = args[0];
        long duration = Long.parseLong(args[1]);
        int fontSize = Integer.parseInt(args[2]);

        // 在EDT中启动Swing应用
        SwingUtilities.invokeLater(() -> {
            SlideshowApp app = new SlideshowApp(path, duration, fontSize);
            app.start();
        });
    }
}

关键改进点说明

  • 自定义ImagePanel:通过paintComponent方法直接绘制缩放后的图片,确保每次窗口大小变化时,图片都会适配新的尺寸。
  • EDT安全的定时器:使用Swing Timer处理幻灯片切换,避免阻塞事件线程,保证界面响应流畅。
  • 组件复用:不再频繁创建新的JLabel,而是复用一个面板来切换显示图片或文本,避免组件堆积。
  • 窗口大小监听:通过ComponentListener在窗口 resize 时触发重绘,实现实时缩放。

内容的提问来源于stack exchange,提问作者nfsu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:07:48