javaswingscalingnimbushighdpi

Java 21 Swing Nimbus: on Windows/Linux high-resolution display the GUI is tiny


There are a lot of old questions regarding the Java Windows/Linux scaling topic with no clear answer. Does some Swing expert know of any updates, for example on Nimbus?

I have coded a really nice Swing application on a computer with 1920x1080 pixel screen. Today I saw the application on a high resolution screen and the app was tiny.

I do not know how to fix this problem. I googled a lot, but could not find a good answer. What I found is JEP 263 https://bugs.openjdk.org/browse/JDK-8055212 It says the issue is resolved. But not how to fix the code?

This is the Nimbus I use:

NimbusLookAndFeel nimbus = new NimbusLookAndFeel();
     UIManager.setLookAndFeel(nimbus);
     UIManager
           .put("control", Color.WHITE);
     UIManager.put("nimbusBlueGrey", ApplicationColors.getLightGrayGold());
     UIManager.put("nimbusBase", ApplicationColors.getDarkGold());
     UIManager.put("textForeground", Color.BLACK);
     UIManager.put("nimbusFocus", ApplicationColors.getSunflowerYellow());
     UIManager
           .put("ToolBar:Button.contentMargins", new Insets(5, 15, 5, 15));
     UIManager
           .put("TextField.background", ApplicationColors.getLightYellow());
     UIManager.put("ComboBox.forceOpaque", false);
     UIManager.put("TitledBorder.border", new Insets(10, 10, 10, 10));
     UIManager.put("TitledBorder.position", TitledBorder.ABOVE_BOTTOM);
     UIManager.put("TitledBorder.font", ApplicationFonts.getGermanFont(16F));
     UIManager.put("TitledBorder.titleColor", Color.GRAY);
     UIManager.put("Table.opaque", false);
     UIManager.put("List.opaque", false);
     UIManager.put("Table.cellRenderer", false);
     UIManager.put("OptionPane.buttonFont", ApplicationFonts.getGermanFont(16F));

     UIManager.put("OptionPane.cancelButtonText", translator.realisticTranslate(Translation.ABBRECHEN));
     UIManager.put("OptionPane.yesButtonText", translator.realisticTranslate(Translation.JA));
     UIManager.put("OptionPane.noButtonText", translator.realisticTranslate(Translation.NEIN));
     UIManager.put("OptionPane.titleText", translator.realisticTranslate(Translation.BILD_LOESCHEN));
     
     UIManager.put("FileChooser.openButtonText", translator.realisticTranslate(Translation.OEFFNEN));
     UIManager.put("FileChooser.cancelButtonText", translator.realisticTranslate(Translation.ABBRECHEN));
     UIManager.put("FileChooser.saveButtonText", translator.realisticTranslate(Translation.SPEICHERN));
     UIManager.put("FileChooser.cancelButtonToolTipText", translator.realisticTranslate(Translation.ABBRECHEN_DER_AUSWAHL));
     UIManager
           .put("FileChooser.saveButtonToolTipText",
                 translator.realisticTranslate(Translation.AUSGEWAEHLTE_DATEI_SPEICHERN));
     UIManager
           .put("FileChooser.openButtonToolTipText",
                 "Ausgewählte Datei öffnen");
     UIManager.put("FileChooser.upFolderToolTipText", "Eine Ebene höher");
     UIManager.put("FileChooser.homeFolderToolTipText", "Home");
     UIManager
           .put("FileChooser.newFolderToolTipText",
                 "Neuen Ordner erstellen");
     UIManager.put("FileChooser.listViewButtonToolTipText", "Liste");
     UIManager.put("FileChooser.detailsViewButtonToolTipText", "Details");
     UIManager.put("FileChooser.lookInLabelText", "Suchen in:");
     UIManager.put("FileChooser.fileNameLabelText", "Dateiname:");
     UIManager.put("FileChooser.filesOfTypeLabelText", "Dateityp:");
     UIManager
           .put("FileChooser.acceptAllFileFilterText",
                 "Alle Dateien (*.*)");
     UIManager.put("FileChooser.folderNameLabelText", "Ordnername:");
     UIManager.put("FileChooser.openDialogTitleText", translator.realisticTranslate(Translation.OEFFNEN));
     UIManager.put("FileChooser.saveDialogTitleText", translator.realisticTranslate(Translation.SPEICHERN));
     UIManager.put("OptionPane.background", ApplicationColors.getWhite());

How to go about scaling on high DPI Windows/Linux screens?

UPDATE

I found this on the internet:

The Per-monitor DPI-aware value means the following:

true - JRE-managed HiDPI
false - IDE-managed HiDPI

If you need to test IDE with scale 1.0 there're two options:

In JRE-managed HiDPI mode:
-Dsun.java2d.uiScale.enabled=true
-Dsun.java2d.uiScale=1.0

In IDE-managed HiDPI mode:
-Dsun.java2d.uiScale.enabled=false
-Dide.ui.scale=1.0

I will test this and report as soon as possible.

UPDATE

The minimal app example would be to much code, since I use my own Layout Managers extended from LayoutManager2. Of course I set sizes on the UI. But it still should scale.

UPDATE

If you want to see the scaling problem, you can download the software Cerebrummi for free from heise.de/download software download The software Cerebrummi needs Java 21 jdk to run. The software Cerebrummi can be set to display in English if you click on the flag in the top row and choose English.

UPDATE

I followed Holgers advice and tested a small example with some features from my large software and IT DID SCALE on high resolution screen. So it is something in my Software that I have to find.

UPDATE I found the offending code:

public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      if (ApplicationImages.getImage() != null)
      {
         float factorWidth = getParent().getWidth() / 1280F;
         float factorHeight = getParent().getHeight() / 859F;
         if (factorWidth < factorHeight)
         {
            int width = (int) (1280F * factorHeight);
            int x = getParent().getWidth() / 2 - width / 2;
            g.drawImage(
              
ApplicationImages.getImage().getScaledInstance(width,
                    getParent().getHeight(), 
BufferedImage.SCALE_SMOOTH),
              x, 0, this);
         }
         else
         {
            int height = (int) (859F * factorWidth);
            int y = getParent().getHeight() / 2 - height / 2;
        
g.drawImage(ApplicationImages.getImage().getScaledInstance(
              getParent().getWidth(), height, 
BufferedImage.SCALE_SMOOTH),
              0, y, this);
        }
     }
  }

It is the large image in the background of the first screenshot!!! How to fix the code?

software1

software2

software3dialog


Solution

  • Thank you very, very much to @Holger.

    Now I learned: Do NOT set the System scaling options!!!

    The offending code could be fixed with:

    public void paintComponent(Graphics g)
       {
          super.paintComponent(g);
          if (ApplicationImages.getImage() != null)
          {
             float factorWidth = 1536 / 1280F; // here is the fix
             float factorHeight = 960 / 859F; // here is the fix
             if (factorWidth < factorHeight)
             {
                int width = (int) (1280F * factorHeight);
                int x = getParent().getWidth() / 2 - width / 2;
                g.drawImage(
                      ApplicationImages.getImage().getScaledInstance(width,
                        getParent().getHeight(), BufferedImage.SCALE_SMOOTH),
                  x, 0, this);
             }
             else
             {
                int height = (int) (859F * factorWidth);
                int y = getParent().getHeight() / 2 - height / 2;
                g.drawImage(ApplicationImages.getImage().getScaledInstance(
                  getParent().getWidth(), height, BufferedImage.SCALE_SMOOTH),
                  0, y, this);
             }
          }
       }