10

I'm currently working on a little Java application, that involves Swing GUIs. On my development PC everything looks fine but when I run it on my MS Surface, some icons seem to be too large for the components (or the components too small for the icons).

Here's what I mean:

scaling issue

Google research has lead me to conclude that this is due to Surface's high resolution and Win8's zooming to let some items appear a little larger. So I reset that zoom to 100% and it actually fixed the bad scaling.

Unfortunately, this doesn't really fix my problem. Everything is far too small without the zoom, so I'd rather not disable it. But is there any clever way to solve this? Can I just "unscale" my program's or Java's icons? Ideally, I would even like upscale the entire frame, because everything is rather small.

Edit: obviously, I've also tried just resizing the actual JFrame but it has no effect on the dialog size. I'm calling the dialog by

JOptionPane.showMessageDialog(frame, msg, "Information", JOptionPane.INFORMATION_MESSAGE);

by the way.

Macklin
  • 167
  • 1
  • 11
  • Oracle is not likely to add high resolution to Swing. You can try JavaFX or [Apache Pivot](http://pivot.apache.org/). – Gilbert Le Blanc Jun 11 '15 at 11:35
  • 1. those Icons (distributed in Java packages, intiliazed in UIManager) has fixed size in pixels, 2. it doesn't react to Icon size in Win8/8.1 display setting, 3. maybe specifics issue with Surface, [you can to test](http://stackoverflow.com/q/8575641/714968) – mKorbel Jun 11 '15 at 13:06

3 Answers3

5

Here is a nasty, hacky, quick-fix solution which will stop the nasty cropping by resizing Swing's own icons to 80%.

In main, add this:

String[] iconOpts = {"OptionPane.errorIcon", 
  "OptionPane.informationIcon", 
  "OptionPane.warningIcon", 
  "OptionPane.questionIcon"};
for (String key : iconOpts) {
  ImageIcon icon = (ImageIcon) UIManager.get(key);
  Image img = icon.getImage();
  BufferedImage bi = new BufferedImage(
          img.getWidth(null), img.getHeight(null), 
          BufferedImage.TYPE_INT_ARGB);
  java.awt.Graphics g = bi.createGraphics();
  g.drawImage(img, 0, 0, 
          (int) (img.getWidth(null) * 0.8), 
          (int) (img.getHeight(null) * 0.8), null);
  ImageIcon newIcon = new ImageIcon(bi);
  UIManager.put(key, newIcon);
}

You might want to first check whether this is actually required - Windows 8/10 defaults to 125% but some people will switch it back to 100%. I haven't found an elegant way to do this, but something along these lines will give you an idea:

java.awt.Font font = (java.awt.Font) UIManager.get("Label.font");
if (font.getSize() != 11) {
    //resize icons in here
}
rosa
  • 108
  • 1
  • 5
  • Thanks for the hint. But it also worked setting the scale to 1.0, I mean, instead of using (int) (img.getWidth(null) * 0.8), (int) (img.getHeight(null) * 0.8) If you use (int) (img.getWidth(null) * 1.0), (int) (img.getHeight(null) * 1.0) So, it doesn't seem to be scale related, but origin related... I don't know exactly. – dannyxyz22 Jul 04 '16 at 13:13
  • Speedy workarounds, nice! Nastier SOLUTIONS often imply excellent hacking...or let's call it...problem solving skills! – Richard Jessop Jul 29 '22 at 12:10
2

Most Swing Look & Feels don't support high DPI at all, not even Nimbus even though it's supposed to be scalable. I found some old blog posts saying that Nimbus might eventually offer high DPI scaling, but apparently that never happened.

The one exception is System LAF but its default font is ~10% smaller than the actual system font size, at all DPI settings. Moreover, System must be selected explicitly as described here: http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html

There's no single scaling factor that you could set in Swing, either. The specific LAF has to provide code to handle scaling. So the best you can do is select System and hope it's good enough.

However, JavaFX does correctly and automatically scale all the way up to 150% on my system. If at all possible, I suggest you use JavaFX to build your GUI.

edit: I made a couple small test programs and took comparison screenshots for various GUI frameworks, Swing themes, and DPI settings. This might be informative for people reading this question: http://kynosarges.org/GuiDpiScaling.html

gmetax
  • 3,853
  • 2
  • 31
  • 45
2

Based on rosa's answer i created a shorter less verbose variant:

String[] iconOpts = {"OptionPane.errorIcon", 
    "OptionPane.informationIcon", 
    "OptionPane.warningIcon", 
    "OptionPane.questionIcon"};
for (String key : iconOpts) {
    ImageIcon icon = (ImageIcon) UIManager.get(key);
    Image img = icon.getImage();
    ImageIcon newIcon = new ImageIcon(img.getScaledInstance(img.getWidth(null), 
        img.getHeight(null), 0));
    UIManager.put(key, newIcon);
}  

P.S.: Due to the reputation system i was not able to comment to rosa's post.

Edit: It seems to me like Java 10 has included a fix for highdpi scaling. So maybe check the java version first before using any of the solutions here.

Crigges
  • 1,083
  • 2
  • 15
  • 28