如何实现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
相关产品推荐
相关产品推荐

