0

On my new HD screen with Windows 11, it is indispensable to set the display settings to 125% to be able to read text, but the icons are getting resized too. I don't get this default behaviour of enlarging icons that can't be enlarged. Obviously it can't look good once resized. I wrote a workaround with CustomMultiResolutionImage to put some transparent padding instead of enlarging the images. It worked for me on 2 of the icons "newFolder" and "upFolder" of the JFileChooser, but not on "viewMenu".

import java.awt.Image;
import java.awt.image.BaseMultiResolutionImage;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.stream.Stream;

import javax.imageio.ImageIO;
import javax.swing.*;

public class Main {


    static {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
        Stream.of("newFolder", "upFolder", "viewMenu").forEach(Main::adaptFileChooserIconKey);
    }

    private static void adaptFileChooserIconKey(String shortKey) {
        String key = getFileChooserIconKey(shortKey);
        if (UIManager.get(key) instanceof ImageIcon imageIcon) {
            UIManager.put(key, new ImageIcon(new CustomMultiResolutionImage(imageIcon.getImage())));
        }
    }

    private static String getFileChooserIconKey(String shortKey) {
        return "FileChooser." + shortKey + "Icon";
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new JFileChooser().showOpenDialog(new JFrame());
        });
    }

    static class CustomMultiResolutionImage extends BaseMultiResolutionImage {

        private static final int DEFAULT_IMAGE_COUNT = 10;

        public CustomMultiResolutionImage(Image baseImage, int imageCount) {
            super(createLargerImages(baseImage, imageCount));
        }

        public CustomMultiResolutionImage(Image baseImage) {
            this(baseImage, DEFAULT_IMAGE_COUNT);
        }

        public CustomMultiResolutionImage(String iconPath) throws IOException {
            this(iconPath, DEFAULT_IMAGE_COUNT);
        }

        public CustomMultiResolutionImage(String iconPath, int imageCount) throws IOException {
            this(ImageIO.read(CustomMultiResolutionImage.class.getResource(iconPath)), imageCount);
        }

        private static Image[] createLargerImages(Image baseImage, int imageCount) {
            int baseWidth = baseImage.getWidth(null);
            int baseHeight = baseImage.getHeight(null);
            Image[] images = new Image[imageCount + 1];
            images[0] = baseImage;
            for (int i = 1; i < images.length; i++) {
                images[i] = new BufferedImage(baseWidth + 2 * i, baseHeight + 2 * i, BufferedImage.TYPE_INT_ARGB);
                images[i].getGraphics().drawImage(baseImage, i, i, null);
            }
            return images;
        }

        @Override
        public Image getResolutionVariant(double destImageWidth, double destImageHeight) {
            return super.getResolutionVariant(Math.round(destImageWidth), Math.round(destImageHeight));
        }
    }
}
Sybuser
  • 735
  • 10
  • 27
  • 1
    Code doesn't compile for me: 1) there are no import statements 2) **if (UIManager.get(key) instanceof ImageIcon imageIcon) {** - I've never seen syntax like that. – camickr Dec 16 '21 at 15:13
  • If you recompile your code to Java 8, then you control the size of the text and images. – Gilbert Le Blanc Dec 16 '21 at 15:22
  • @camickr : it's the java 16 instanceof pattern matching : https://docs.oracle.com/en/java/javase/16/language/pattern-matching-instanceof-operator.html – Sybuser Dec 16 '21 at 15:40
  • @Sybuser, whatever, it doesn't compile in older versions and is not required to demonstrate the described problem, so you are limiting the number of people that can test your code. – camickr Dec 16 '21 at 17:01
  • According to the the [UIManager Defaults](https://tips4java.wordpress.com/2008/10/09/uimanager-defaults/), those are not the key values that should be used to access the Icon. Also, maybe this link: https://stackoverflow.com/questions/65742162/how-to-fix-the-blurry-image-when-i-run-my-java-swing-project/65742492#65742492 will help. – camickr Dec 16 '21 at 17:13
  • 1
    @camickr since this is about UI scaling, which has changed multiple times since Java 8, there is no point in trying to reproduce the behavior in older versions. – Holger Dec 17 '21 at 11:15
  • 2
    It doesn’t work because the image you’re scaling is not the image you’re seeing. `WindowsFileChooserUI.installComponents(…)` is drawing your image into another `BufferedImage`, to add the down arrow triangle and create another `ImageIcon`. I don’t know how to get hands on that resource. That’s all hard-coded. – Holger Dec 17 '21 at 11:51

0 Answers0