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

如何实现HiDPI屏幕上无缩放且尺寸适配的Java图片组件?

HiDPI屏幕下JLabel无缩放显示图片且首选尺寸适配方案

要在HiDPI屏幕上实现图片无缩放显示,用JLabel作为首选组件时,通过重写paintComponent修改AffineTransform可实现图片不缩放,但会出现组件首选尺寸被系统缩放因子放大、实际尺寸大于图片的问题。以下是修正方案:

核心思路

Swing在HiDPI环境下会自动根据系统缩放因子调整组件的首选尺寸,要让JLabel的尺寸严格匹配图片原始像素,需重写getPreferredSize方法直接返回图片的原始宽高,同时保留绘制阶段的无缩放变换逻辑,避免图片被缩放。

修改后的完整代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

public class UnscaledImage extends JPanel {

    private AffineTransform noChangeTransform = new AffineTransform();
    private JLabel imageLabel;
    private JLabel colorLabel = new JLabel("Color");
    private BufferedImage image;

    public UnscaledImage() {
        initUI();
        packAndShow("Unscaled Image");
    }

    public void initUI() {
        setLayout(new BorderLayout());
        ImageIcon imageIcon = (ImageIcon) UIManager.getIcon("OptionPane.warningIcon");
        image = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        g2d.drawImage(imageIcon.getImage(), 0, 0, null);
        g2d.dispose();

        imageLabel = new JLabel(imageIcon) {
            @Override
            public Dimension getPreferredSize() {
                // 直接返回图片的原始像素尺寸,不受系统缩放影响
                return new Dimension(image.getWidth(), image.getHeight());
            }

            @Override
            public void paintComponent(Graphics g) {
                Graphics2D g2d = (Graphics2D) g;
                AffineTransform oldTransform = g2d.getTransform();
                // 应用无缩放变换,保证图片按原始像素绘制
                g2d.setTransform(noChangeTransform);
                super.paintComponent(g);
                // 恢复原有变换,不影响其他组件绘制
                g2d.setTransform(oldTransform);
            }
        };

        imageLabel.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent me) {
                int mouseX = me.getX();
                int mouseY = me.getY();
                // 组件尺寸等于图片原始尺寸,直接用鼠标坐标取色
                if (mouseX < image.getWidth() && mouseY < image.getHeight()) {
                    int color = image.getRGB(mouseX, mouseY);
                    colorLabel.setBackground(new Color(color));
                }
            }
        });

        colorLabel.setOpaque(true);
        colorLabel.setBackground(Color.WHITE);
        add(imageLabel, BorderLayout.CENTER);
        add(colorLabel, BorderLayout.SOUTH);
    }

    public void packAndShow(String title) {
        JFrame frame = new JFrame(title);
        frame.add(this);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public final static void main(String[] args) {
        SwingUtilities.invokeLater(UnscaledImage::new);
    }
}

关键修改说明

  • 重写getPreferredSize:直接返回图片的原始宽高,让布局管理器使用这个尺寸,彻底避免系统缩放因子对组件尺寸的影响,组件大小始终和图片原始像素一致。
  • 简化paintComponent逻辑:移除了原来动态调整组件尺寸和调用pack()的冗余代码,只保留变换的保存、设置和恢复,保证图片绘制时不被缩放,同时不干扰其他组件的正常渲染。
  • 修正鼠标坐标计算:因为组件尺寸已经和图片原始尺寸一致,鼠标事件的坐标直接对应图片的像素坐标,不需要再乘以缩放因子,取色逻辑更简洁准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:20:29