Вот что я пробовал:
- На изображении ниже, чтобы создать «32, масштабированное до 16», я вызвал imageIcon.getImage().getScaledInstance(16, 16, Image.SCALE_SMOOTH) Этот метод был написан задолго до изобретения экранов с высоким разрешением и возвращает изображение с низким разрешением. в половинном размере.
- Чтобы создать «16-пиксельный вариант», я создал MultiResolutionImage с 16-пиксельными и 32-пиксельными вариантами и вызвал multiResImage.getResolutionVariant(16, 16), который запрашивает 16-пиксельный вариант, надеясь, что он уменьшит 32-пиксельный вариант. Он использовал 32-пиксельный вариант, но в полном размере. Это заставляет меня задуматься, для чего нужен этот класс.
- Чтобы создать «Кнопку половинного размера», я создал подкласс ImageIcon половинного размера и переопределил три метода, используемые для рисования изображения. Частично это сработало. Это было единственное решение, которое рисовало изображение в правильном размере и разрешении, но помещало изображение не в то место. (Код этого класса приведен ниже.)

Вот класс ImageIcon половинного размера:
public static class HalfSizeIcon extends ImageIcon {
private static final float scale = 0.5f;
public HalfSizeIcon(ImageIcon icon) {
super(icon.getImage());
if (icon.getDescription() != null) {
setDescription(icon.getDescription());
}
}
@Override
public synchronized void paintIcon(
final Component c,
final Graphics g,
final int x,
final int y) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
g2.scale(scale, scale);
super.paintIcon(c, g2, x, y);
g2.setTransform(savedTransform);
}
@Override
public int getIconWidth() {
return Math.round(scale * (super.getIconWidth()));
}
@Override
public int getIconHeight() {
return Math.round(scale * (super.getIconHeight()));
}
}
Вот полный минимальный воспроизводимый пример без значка, который необходим для его запуска.
import java.awt .*;
import java.awt.geom.AffineTransform;
import java.awt.image .*;
import java.net.URL;
import javax.swing .*;
@SuppressWarnings("HardCodedStringLiteral")
public class IconFamilyBug extends JPanel {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new IconFamilyBug(), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
IconFamilyBug() {
super(new GridBagLayout());
Image dir16 = loadImage("add_16.png");
Image dir32 = loadImage("add_32.png");
final var SMALL = 16;
final var BIG = 32;
Image scaledImage
= dir32.getScaledInstance(SMALL, SMALL, Image.SCALE_SMOOTH);
MultiResolutionImage multiResImage
= new BaseMultiResolutionImage(dir16, dir32);
Image var16 = multiResImage.getResolutionVariant(SMALL, SMALL);
Image var32 = multiResImage.getResolutionVariant(BIG, BIG);
int row = 0;
addButton(dir16, "16-bit image", row++);
addButton(scaledImage, "32 scaled to 16", row++);
addButton(var16, "16-pixel variant", row++);
addButton(var32, "32-pixel variant", row++);
Constraint c = new Constraint().y(row);
ImageIcon half32 = new HalfSizeIcon(new ImageIcon(dir32));
JButton halfSizeButton = new JButton(half32);
halfSizeButton.setToolTipText("Half Size Button");
add(halfSizeButton, c);
add(new JLabel(halfSizeButton.getToolTipText()), c);
final Color transparent = new Color(255, 0, 0, 0);
setBorder(BorderFactory.createMatteBorder(10, 10, 10, 10, transparent));
}
private Image loadImage(String fileName) {
URL url = getClass().getResource(fileName);
return Toolkit.getDefaultToolkit().getImage(url);
}
private void addButton(Image image, String name, int row) {
Constraint c = new Constraint().y(row);
JButton button = new JButton(new ImageIcon(image));
button.setToolTipText(name);
add(button, c);
add(new JLabel(name), c);
}
public static class HalfSizeIcon extends ImageIcon {
private static final float scale = 0.5f;
public HalfSizeIcon(ImageIcon icon) {
super(icon.getImage());
if (icon.getDescription() != null) {
setDescription(icon.getDescription());
}
}
@Override
public synchronized void paintIcon(
final Component c,
final Graphics g,
final int x,
final int y) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
g2.scale(scale, scale);
super.paintIcon(c, g2, x, y);
g2.setTransform(savedTransform);
}
@Override
public int getIconWidth() {
return Math.round(scale * (super.getIconWidth()));
}
@Override
public int getIconHeight() {
return Math.round(scale * (super.getIconHeight()));
}
}
/**
*
Feel free to expand this class for your own use by adding more chainable
* setters, following the example of the y() method below, which could also be
* named row() or gridY(). This is a much more convenient way to use
* GridBagConstraints. I've found that it's also helpful to add two-parameter
* methods like {@code Constraint at(int gridX, int gridY)}, along with others
* for weight(), pad(), and gridSize().
*/
@SuppressWarnings("AssignmentToSuperclassField")
public static class Constraint extends GridBagConstraints {
Constraint() {
super();
fill = GridBagConstraints.BOTH;
gridx = GridBagConstraints.RELATIVE;
}
public Constraint y(int gridY) { // All parameters should be set this way.
gridy = gridY;
return this;
}
@SuppressWarnings("UseOfClone")
@Override
public Constraint clone() {
return (Constraint) super.clone();
}
}
}