Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JOptionPane icon gets cropped in Windows 10

I am using the following code to present an error dialog in Java Swing:

JOptionPane.showMessageDialog(null, "Arquivo de imagem não encontrado. Por gentileza, altere o caminho do arquivo.", "Erro",  JOptionPane.ERROR_MESSAGE);

using Windows 10 default look and feel through:

UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

But the icon looks cropped, like this:

Dialog with cropped icon

Any ideas on how to solve that?

Here is the SSCCE:

import javax.swing.JOptionPane;
import javax.swing.UIManager;

public class SSCCE {
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            JOptionPane.showMessageDialog(null, "Error message", "Error",  JOptionPane.ERROR_MESSAGE);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

}
like image 605
dannyxyz22 Avatar asked Nov 25 '15 21:11

dannyxyz22


People also ask

How do I change font size in JOptionPane?

There is an easy way to change the default font in JOptionPane . Pass a string modified in html format, which means you can either use <font> tag or even CSS. Using <font> tag. Using CSS.

What should I import into JOptionPane?

The JOptionPane class is a part of the javax. swing package, so you need to add this import javax. swing. JOption Pane statement to the beginning of any proram that uses this class.

How do I close JOptionPane?

9. JOptionPane closing coderanch.com. If it's really safe to just kill all JOptionPanes you can do something like this: public static void main(String[] args) { new Thread() { public void run() { for (int i = 0; i < 3; i++) { try { Thread.


2 Answers

Looks like Oracle has finally taken notice of this and will fix it in JDK 9, but for the time being here's a qiuck, hacky and Windows dependent solution for those not willing to provide custom icons.

Insert this code after your call to UIManager.setLookAndFeel():

try
{
    String[][] icons =
    {
        {"OptionPane.errorIcon", "65581"},
        {"OptionPane.warningIcon", "65577"},
        {"OptionPane.questionIcon", "65579"},
        {"OptionPane.informationIcon", "65583"}
    };
    //obtain a method for creating proper icons
    Method getIconBits = Class.forName("sun.awt.shell.Win32ShellFolder2").getDeclaredMethod("getIconBits", new Class[]{long.class, int.class});
    getIconBits.setAccessible(true);
    //calculate scaling factor
    double dpiScalingFactor = Toolkit.getDefaultToolkit().getScreenResolution() / 96.0;
    int icon32Size = (dpiScalingFactor == 1)?(32):((dpiScalingFactor == 1.25)?(40):((dpiScalingFactor == 1.5)?(45):((int) (32 * dpiScalingFactor))));
    Object[] arguments = {null, icon32Size};
    for (String[] s:icons)
    {
        if (UIManager.get(s[0]) instanceof ImageIcon)
        {
            arguments[0] = Long.valueOf(s[1]);
            //this method is static, so the first argument can be null
            int[] iconBits = (int[]) getIconBits.invoke(null, arguments);
            if (iconBits != null)
            {
                //create an image from the obtained array
                BufferedImage img = new BufferedImage(icon32Size, icon32Size, BufferedImage.TYPE_INT_ARGB);
                img.setRGB(0, 0, icon32Size, icon32Size, iconBits, 0, icon32Size);
                ImageIcon newIcon = new ImageIcon(img);
                //override previous icon with the new one
                UIManager.put(s[0], newIcon);
            }
        }
    }
}
catch (Exception e)
{
    e.printStackTrace();
}

Why this works

On Windows, icons provided to applications are already scaled by the current DPI setting (96 = no scaling, 120 = +25%, 144 = +50%). Unfortunatelly, Java always assumes that icons are of size either 16x16 or 32x32, which is not the case. The code above utilizes a native method sun.awt.shell.Win32ShellFolder2.getIconBits() used by Java to obtain OS icons, but provides appropriate sizes. This approach may become unusable in the future, as Win32ShellFolder2 is not part of the API and may be modified or removed entirely, but so far this is the only approach preserving the native icons.

like image 167
mkJ720 Avatar answered Oct 05 '22 23:10

mkJ720


mkJ720's answer works well, but the icon ID's are off. Here are the corrected ones:

String[][] icons = {
    {"OptionPane.warningIcon",     "65581"},
    {"OptionPane.questionIcon",    "65583"},
    {"OptionPane.errorIcon",       "65585"},
    {"OptionPane.informationIcon", "65587"}
};
like image 32
Sean Niemann Avatar answered Oct 06 '22 01:10

Sean Niemann