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

Inconsistant painting of components when Windows display scaling > 100%

XMLWordPrintable

    • 9
    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Windows 11 24H2

      A DESCRIPTION OF THE PROBLEM :
      Java seems to paint the background of a component in two different ways depending on when the painting is done. It looks like a rounding issue when the display scaling is greater than 100%. The difference is a 1 pixel line on the right or at the bottom of the component that is not repainted. One consequence is trailing segments appearing when components are dragged across a container.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Set the display scaling to 125%.
      Create a JPanel with black background in a JFrame at (x, y), with width and height 40.
      Through a Timer (10 ms is enough), change the background to white and call the repaint() method of the panel.
      Try with different values for (x,y): (0,0), (0,1), (0,2)...

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The panel should be a white square.
      ACTUAL -
      Depending on the values of (x,y), black 1 pixel width lines appear at the right and/or at the bottom of the square.
      Note that there is a regular pattern in the way the lines appear as you increase the x and y values.

      ---------- BEGIN SOURCE ----------
      package HDPI;

      import java.awt.*;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.awt.geom.AffineTransform;

      import javax.swing.JButton;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JPanel;
      import javax.swing.SwingUtilities;
      import javax.swing.Timer;


      @SuppressWarnings("serial")
      public class HdpiPaintIssue extends JFrame {

      public class TestPanel extends JPanel {

      @Override
      protected void paintComponent(Graphics g) {

      super.paintComponent(g);

      updateInfo((Graphics2D) g);
      }

      private void updateInfo(Graphics2D g2d) {

      Integer X = getX();
      Integer Y = getY();
      labelX.setText("x = " + X.toString());
      labelY.setText("y = " + Y.toString());

      final AffineTransform t = g2d.getTransform();
      final Double tx = t.getTranslateX();
      final Double ty = t.getTranslateY();

      labelTX.setText("tx = " + tx.toString());
      labelTY.setText("ty = " + ty.toString());
      }
      }

      private final Color light = Color.white;
      private final Color dark = Color.black;

      private TestPanel panel = null;
      private JLabel labelX = null;
      private JLabel labelY = null;
      private JLabel labelTX = null;
      private JLabel labelTY = null;

      public HdpiPaintIssue() {

      super("HDPI issue");
      setSize(250, 200);
      setLocationRelativeTo(null);
      setDefaultCloseOperation(DISPOSE_ON_CLOSE);
      setVisible(true);
      setFocusable(true);
      requestFocus();

      getContentPane().setLayout(null);


      // Labels to display a few values

      labelX = new JLabel();
      labelX.setBounds(100, 2, 40, 24);
      getContentPane().add(labelX);

      labelY = new JLabel();
      labelY.setBounds(100, 14, 40, 24);
      getContentPane().add(labelY);

      labelTX = new JLabel();
      labelTX.setBounds(150, 2, 100, 24);
      getContentPane().add(labelTX);

      labelTY = new JLabel();
      labelTY.setBounds(150, 14, 100, 24);
      getContentPane().add(labelTY);

      JLabel lbVersion = new JLabel("java.version = " + System.getProperty("java.version"));
      lbVersion.setBounds(50, 140, 120, 24);
      getContentPane().add(lbVersion);


      // Panel to be moved

      panel = new TestPanel();
      panel.setBounds(0, 0, 40, 40);
      panel.setOpaque(true);
      panel.setBackground(dark);
      getContentPane().add(panel);

      delayedRepaint();


      // Buttons to move the panel

      addButton("<", 80, 80);
      addButton(">", 140, 80);
      addButton("^", 110, 50);
      addButton("v", 110, 110);
      }

      private void addButton(String text, int x, int y) {

      JButton b = new JButton(text);
      b.setBounds(x, y, 50, 30);
      getContentPane().add(b);
      b.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                  
                   Point pt = panel.getLocation();
                   switch(text) {
                   case "<":
                   pt.x = pt.x - 1;
                   break;
                   case ">":
                   pt.x = pt.x + 1;
                   break;
                   case "^":
                   pt.y = pt.y - 1;
                   break;
                   default:
                   pt.y = pt.y + 1;
                   }
           panel.setBackground(dark);
           panel.setLocation(pt); // <- setLocation() triggers a dark painting
           delayedRepaint(); // <- we trigger a light painting on top of it
                  }
              });
      }

      private void delayedRepaint() {

      Timer timer = new Timer(10, new ActionListener() { // A short delay is required for the issue to appear
      @Override
      public void actionPerformed(ActionEvent arg0) {
      panel.setBackground(light);
                   panel.repaint();
      }
      });
      timer.setRepeats(false);
      timer.start();
      }

      public static void main(String args[]) {

      SwingUtilities.invokeLater(new Runnable() {
      public void run() {
      new HdpiPaintIssue();
      }
      });
      }
      }
      ---------- END SOURCE ----------

            azvegint Alexander Zvegintsev
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: