I have png icons and use them as icons in JButton / JLabel.
The problem is that the image displayed at runtime is larger than the original icon, and because of this resizing, it's super ugly.
Here is an example:
Original icon (left) and how it's rendered in the JButton (right)
The source code for this minimal example is simply:
public class Main {
public static void main(String... args) {
JFrame frame = new JFrame("Test");
frame.setBounds(0, 0, 120, 80);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new FlowLayout());
ImageIcon icon = new ImageIcon("icon.png");
frame.getContentPane().add(new JButton("Test", icon));
frame.setVisible(true);
}
}
Is this expected? If not, how can I avoid this? I tried many things around forcing the size of the image, the button, etc. but could not get a proper image displayed.
I have tested with icons of various sizes: 16x16, 17x17, 18x18, 19x19, 20x20, and each time the icon displayed on the JButton is a bit larger than the original which makes it look ugly:
Thank you!
Cheers.
解决方案
This is because you are using Windows scaling. The entire component is scaled, both the icon and the text.
You could turn the scaling of the Icon off by using a wrapper Icon:
import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
public class NoScalingIcon implements Icon
{
private Icon icon;
public NoScalingIcon(Icon icon)
{
this.icon = icon;
}
public int getIconWidth()
{
return icon.getIconWidth();
}
public int getIconHeight()
{
return icon.getIconHeight();
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
Graphics2D g2d = (Graphics2D)g.create();
AffineTransform at = g2d.getTransform();
int scaleX = (int)(x * at.getScaleX());
int scaleY = (int)(y * at.getScaleY());
int offsetX = (int)(icon.getIconWidth() * (at.getScaleX() - 1) / 2);
int offsetY = (int)(icon.getIconHeight() * (at.getScaleY() - 1) / 2);
int locationX = scaleX + offsetX;
int locationY = scaleY + offsetY;
AffineTransform scaled = AffineTransform.getScaleInstance(1.0 / at.getScaleX(), 1.0 / at.getScaleY());
at.concatenate( scaled );
g2d.setTransform( at );
icon.paintIcon(c, g2d, locationX, locationY);
g2d.dispose();
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI()
{
JButton button = new JButton( "Button" );
NoScalingIcon icon = new NoScalingIcon( new ImageIcon("box.jpg") );
button.setIcon( icon );
JPanel panel = new JPanel( );
panel.add( button );
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(panel);
f.setSize(200, 200);
f.setLocationRelativeTo( null );
f.setVisible(true);
}
}
The scaling adjustment will position the Icon at the top/left of the button area.
The offset adjustment will then attempt to center the Icon in the scaled icon painting area.
Using the default transform will have a scaling factor of 0 for the Icon.