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

Swing中JFrame显示后缩放图像无法显示的技术问题

全屏图像查看器初始化后图像不显示的解决方案

我正在为即时通讯应用开发一款全屏图像查看器,遇到以下问题:JFrame设置为可见后,缩放后的图像无法显示,只有将窗口最小化再恢复后才能看到。调试发现窗口显示后重写的paintComponent()方法甚至未被调用。

原代码

import java.awt.event.KeyEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyListener;
import java.awt.image.ImageObserver;
import java.net.URL;
import javax.imageio.ImageIO;

public class Overlay extends JFrame {

    public Overlay() {
        super();
        this.setUndecorated(true);
        getRootPane().setOpaque(true);
        panel = new JPanel();
        panel.setBackground(new Color(12,12,12));
        setLayout(new CardLayout());
        add(panel);
        panel.setBorder(BorderFactory.createEmptyBorder(90, 90, 90, 90));

        this.addKeyListener(new KeyListener() {

            @Override
            public void keyTyped(KeyEvent e) {}

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                    setVisible(false);
                    dispose();
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {}
        });
    }

    public class ImageViewer extends JPanel {

        public ImageViewer(String src) {
            this.src = src;
            setOpaque(false);
            try {
                img = ImageIO.read(new URL(src));
                int imgHeight = img.getHeight(observer);
                if (imgHeight > 0) {
                    w = (int) (h * ((double) img.getWidth(null) / imgHeight));
                }
            } catch (IOException ex) {}
        }

        public ImageViewer(String src, int width, int height) {
            setOpaque(false);
            setPreferredSize(new Dimension(width, height));
            setMinimumSize(new Dimension(width, height));
            setMaximumSize(new Dimension(width, height));
            w = width;
            h = height;
            this.src = src;
            try {
                img = ImageIO.read(new URL(src));
                int imgHeight = img.getHeight(observer);
                if (imgHeight > 0) {
                    w = (int) (h * ((double) img.getWidth(null) / imgHeight));
                }
            } catch (IOException ex) {}
        }

        ImageObserver observer = new ImageObserver() {
            @Override
            public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
                if (height == 0) return false;
                w = (int) (h * ((double) width / height));
                if (getParent() != null) getParent().repaint();
                return true;
            }
        };

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (img == null) return;
            Graphics2D g2d = (Graphics2D) g;
            img.getHeight(observer);
            int x = (int) (getWidth() - w) / 2;
            int y = (int) (getHeight() - h) / 2;
            System.out.println(x + ", " + y);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            g2d.drawImage(img, x, y, w, h, null);
        }

        private int w;
        private int h;

        private Image img;
        private String src = null;
    }

    public void showContent() {
        try {
            GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
            setVisible(true);
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    int width = (int) (getBounds().getWidth() * 0.7 + 0.4);
                    int height = (int) (width / 16 * 9 + 0.4);
                    System.err.println(width + "x" + height);
                    ImageViewer viewer = new ImageViewer("http://popov654.pp.ru/copybox/image.jpg", width, height);
                    panel.setLayout(new BorderLayout());
                    panel.add(viewer);
                    try {
                        Thread.sleep(100);
                        viewer.repaint();
                    } catch (InterruptedException ex) {}
                }
            });
        } catch (Exception error) {}
    }

    public static void main(String[] args) {
        new Overlay().showContent();
    }

    JPanel panel;
}

问题根源

  1. UI更新时机错误:窗口已设为可见后才添加ImageViewer组件,但未通知Swing重新计算布局并刷新界面。
  2. 阻塞EDT线程:Thread.sleep(100)会阻塞事件调度线程(EDT),导致UI无法及时响应重绘请求。
  3. 全屏模式重绘触发缺失:全屏窗口的UI更新需要明确触发布局和重绘操作,否则系统不会自动触发。

修复方案

修改showContent()方法,移除阻塞EDT的代码,并在添加组件后强制触发布局和重绘:

public void showContent() {
    try {
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                int width = (int) (getBounds().getWidth() * 0.7 + 0.4);
                int height = (int) (width / 16 * 9 + 0.4);
                System.err.println(width + "x" + height);
                ImageViewer viewer = new ImageViewer("http://popov654.pp.ru/copybox/image.jpg", width, height);
                panel.setLayout(new BorderLayout());
                panel.add(viewer);
                // 通知面板重新计算布局并刷新
                panel.revalidate();
                panel.repaint();
            }
        });
        setVisible(true);
    } catch (Exception error) {}
}

额外优化建议

  • 替换KeyListener为KeyBindings:KeyListener依赖组件焦点,使用KeyBindings可确保ESC键在任何情况下都能触发关闭操作,示例代码:
    // 在Overlay构造函数中替换KeyListener
    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
    getRootPane().getActionMap().put("close", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            setVisible(false);
            dispose();
        }
    });
    
  • 异步加载图像:使用SwingWorker异步加载网络图像,避免阻塞EDT导致UI卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:55:21