Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8272707

Swing components and fonts incorrectly sized in Windows LAF on scaled display

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      OS: Windows 10 version 20H2 (though bug seen on previous versions)
      Java JRE: 11.0.12
      JVM Arch: amd64

      64-bit operating system, x64-based processor
      Edition Windows 10 Enterprise
      Version 20H2
      OS build 19042.1110
      Experience Windows Feature Experience Pack 120.2212.3530.0
       

      A DESCRIPTION OF THE PROBLEM :

      We recently upgraded our Swing-based Java desktop application (which uses System LAF) from Java 8 to Java 11 and since then have seen very significant sizing and layout issues on scaled monitors, on machines running Windows 10. A common setup is to have a laptop with a big monitor attached, scaled at 100%, while the laptop screen is scaled at 125% or 150%. We are finding that it is near impossible to use our application on the scaled monitor(s) due to components and text being truncated and in some cases unreadable or unusable. Combo boxes drop down in strange locations nowhere near the original component, dialog text is truncated so much that it is almost invisible, and colour ramps drawn with Java2D primitives have white lines down them (precision errors?)

      To observe this issue, run the attached demo program with vanilla Swing components on a Windows 10 machine, starting on an unscaled (100%) display and then dragging the frame onto a second, scaled display. You will see the components and text being truncated, and additional sizing/layout issues when you click the button and drop down the combo.

      This scenario is 100% reproducible by all of our team members so I am very surprised I have not found an open issue. I am aware that HiDPI support was introduced in Java 9 and this is the cause of the changed behaviour.
      I have found other issues in the bug database that look related, but these are reported as fixed, whereas this is definitely not.

      Note: I have tried the same thing using Java 15 and 16 JREs and found exactly the same behaviour.

      keywords #swing #hidpi #scaling #windows

      REGRESSION : Last worked in version 8

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      CASE A:
      1. Set up a Windows 10 machine with main display scaled at 100% and a secondary display scaled to 125%.
      2. Run the attached example using a JRE version 11 or later so that it appears on the main display.
      3. Confirm components are laid out correctly:
          - Click the button to confirm the message dialog is laid out correctly. Click OK to dismiss dialog.
          - Click the combo box arrow to drop down the list.
      4. Drag the frame onto your second, scaled display and observe how the components are laid out. Repeat the steps in 3 (click button, open dropdown).

      CASE B:
      Set the primary display to be the scaled one and re-run the test.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      CASE A:
      At 3: components laid out correctly with default label font Tahoma 11.
      At 4: components should look and behave basically the same as in 3.

      CASE B:
      as above
      ACTUAL -
      CASE A:
      At 3: components laid out correctly on primary, unscaled display.
      At 4:
       - In the main panel, the font has noticeably changed in appearance and the kerning is quite bad, with large gaps between some letters. The top label and the combo have been truncated on the right (this seems worse at 125% compared to 150%).
       - When the button is clicked to pop up the JOptionPane message dialog, the dialog appears in quite the wrong spot (sometimes on the other monitor). The layout of the dialog itself is quite bad with the OK button being truncated on the bottom and the text being truncated on the right (worse at 150% than 125%).
       - The first time the dropdown is clicked, the dropdown list panel will appear disconnected from its host component (subsequent dropdowns are OK).

      CASE B:
      At 3: (on primary, scaled display)
       - The initial layout of the panel on the primary scaled display is quite different, with the text on JLabels, JButtons etc very small (Tahoma 9 at 125% and Tahoma 7 at 150%). Label and dropdown are quite truncated.
       - The message dialog is correctly laid out with a MUCH bigger font than in the original panel. Combo box behaves correctly.
      At 4:
       - text is even tinier on the 100% monitor. Otherwise the scaling seems to behave more as you would expect, though the first dropdown still appears in the wrong spot.

      ---------- BEGIN SOURCE ----------
      import java.awt.Font;

      import javax.swing.BoxLayout;
      import javax.swing.JButton;
      import javax.swing.JComboBox;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JOptionPane;
      import javax.swing.JPanel;
      import javax.swing.JTextField;
      import javax.swing.UIManager;

      public class SwingTester extends JFrame
      {
         private JLabel label1;
         private JLabel label2;
         private JTextField textField;
         private JButton button;
         private JComboBox<String> combo;
         
         static String[] NAMES = {"Dropdown", "Is", "This", "In", "The", "Right", "Place?"};

         public SwingTester()
         {
            super("Swing Tester");
            buildGUI();

            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            pack();
         }

         private void buildGUI()
         {
            label1 = new JLabel();
            Font labelFont = label1.getFont();
            label1.setText("Default JLabel font: "
                        + labelFont.getFontName() + " "
                        + labelFont.getSize());
            
            label2 = new JLabel("Default text field font:");
            textField = new JTextField(10);
            textField.setText(textField.getFont().getFontName()
                              + " "
                              + textField.getFont().getSize());
            JPanel panel1 = new JPanel();
            panel1.add(label2);
            panel1.add(textField);
            
            button = new JButton("Click me to see JOptionPane");
            combo = new JComboBox<>(NAMES);
            JPanel panel2 = new JPanel();
            panel2.add(button);
            panel2.add(combo);
            
            JPanel mainPanel = new JPanel();
            
            BoxLayout layout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);
            mainPanel.setLayout(layout);
            mainPanel.setAlignmentX(LEFT_ALIGNMENT);
            
            mainPanel.add(label1);
            mainPanel.add(panel1);
            mainPanel.add(panel2);

            button.addActionListener((event) -> {
               String message = "JOptionPane.showMessageDialog() with some text in it";

               JOptionPane.showMessageDialog(this, message);
            });
            
            this.add(mainPanel);
         }

         public static void main(String[] args) throws Exception
         {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            SwingTester window = new SwingTester();
            window.setLocation(800, 500);
            window.setVisible(true);
         }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The only workaround we have found is to override high DPI scaling on the executable we are using (in this case java.exe). Right click exe, select Properties -> Compatibility, click "Change high DPI Settings", check "Override high DPI scaling behavior", select "System". This returns the application to its previous Java 8, pre-HiDPI support behaviour.

      FREQUENCY : always


            rkannathpari Renjith Kannath Pariyangad
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: