-
Bug
-
Resolution: Unresolved
-
P3
-
11, 17, 18, 19, 20
-
x86_64
-
windows
ADDITIONAL SYSTEM INFORMATION :
Windows 11, jdk-17.0.4.1+1
A DESCRIPTION OF THE PROBLEM :
With Windows set to a fractional scaling (125%), Graphics2D operations are done at inconsistent locations depending on the levels that get repainted. This happens for certain component heights, and certain component locations.
The result for the end-user is that a component is painted, then its state changes and is repainted but the bottom pixels are not updated, leaving ugly traces on screen.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Using the provided test case:
- Press "Repaint all" to repaint the whole UI, and the component gets painted in black.
- Press "Repaint component" to only repaint the component, and the component gets painted in white.
It is possible to increase the top border in case on your setup a different location is needed to trigger the bug.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The component should be completely white.
ACTUAL -
The component is white except for the bottom line that remained black.
See the error in this image: <link>
---------- BEGIN SOURCE ----------
package test.graphics2d;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Graphics2DTestOnHighDpi {
private static int borderSize = 8;
private static boolean isRepaintComponent;
public static void main(String[] args) {
JFrame frame = new JFrame("Graphics2D Test with fractional scaling");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
JPanel northPane = new JPanel(new FlowLayout());
northPane.setBorder(BorderFactory.createEmptyBorder(borderSize, 0, 0, 0));
JPanel componentContainer = new JPanel();
componentContainer.setLayout(new BoxLayout(componentContainer, BoxLayout.LINE_AXIS));
JComponent component = new JComponent() {
@Override
protected void paintComponent(Graphics g) {
g.setColor(isRepaintComponent? Color.WHITE: Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
isRepaintComponent = false;
}
};
component.setPreferredSize(new Dimension(50, 32));
componentContainer.add(component);
northPane.add(componentContainer, BorderLayout.CENTER);
contentPane.add(northPane, BorderLayout.NORTH);
JPanel southPane = new JPanel(new FlowLayout());
JButton increaseBorderButton = new JButton("Increase top margin");
increaseBorderButton.addActionListener((ae) -> northPane.setBorder(BorderFactory.createEmptyBorder(++borderSize, 0, 0, 0)));
southPane.add(increaseBorderButton);
JLabel repaintComponentButton = new JLabel("Repaint Component");
repaintComponentButton.setBorder(BorderFactory.createLineBorder(Color.BLACK));
repaintComponentButton.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
isRepaintComponent = true;
component.repaint();
}
});
southPane.add(repaintComponentButton);
JLabel repaintAllButton = new JLabel("Repaint all");
repaintAllButton.setBorder(BorderFactory.createLineBorder(Color.BLACK));
repaintAllButton.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
frame.repaint();
}
});
southPane.add(repaintAllButton);
contentPane.add(southPane, BorderLayout.SOUTH);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
---------- END SOURCE ----------
FREQUENCY : always
Windows 11, jdk-17.0.4.1+1
A DESCRIPTION OF THE PROBLEM :
With Windows set to a fractional scaling (125%), Graphics2D operations are done at inconsistent locations depending on the levels that get repainted. This happens for certain component heights, and certain component locations.
The result for the end-user is that a component is painted, then its state changes and is repainted but the bottom pixels are not updated, leaving ugly traces on screen.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Using the provided test case:
- Press "Repaint all" to repaint the whole UI, and the component gets painted in black.
- Press "Repaint component" to only repaint the component, and the component gets painted in white.
It is possible to increase the top border in case on your setup a different location is needed to trigger the bug.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The component should be completely white.
ACTUAL -
The component is white except for the bottom line that remained black.
See the error in this image: <link>
---------- BEGIN SOURCE ----------
package test.graphics2d;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Graphics2DTestOnHighDpi {
private static int borderSize = 8;
private static boolean isRepaintComponent;
public static void main(String[] args) {
JFrame frame = new JFrame("Graphics2D Test with fractional scaling");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
JPanel northPane = new JPanel(new FlowLayout());
northPane.setBorder(BorderFactory.createEmptyBorder(borderSize, 0, 0, 0));
JPanel componentContainer = new JPanel();
componentContainer.setLayout(new BoxLayout(componentContainer, BoxLayout.LINE_AXIS));
JComponent component = new JComponent() {
@Override
protected void paintComponent(Graphics g) {
g.setColor(isRepaintComponent? Color.WHITE: Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
isRepaintComponent = false;
}
};
component.setPreferredSize(new Dimension(50, 32));
componentContainer.add(component);
northPane.add(componentContainer, BorderLayout.CENTER);
contentPane.add(northPane, BorderLayout.NORTH);
JPanel southPane = new JPanel(new FlowLayout());
JButton increaseBorderButton = new JButton("Increase top margin");
increaseBorderButton.addActionListener((ae) -> northPane.setBorder(BorderFactory.createEmptyBorder(++borderSize, 0, 0, 0)));
southPane.add(increaseBorderButton);
JLabel repaintComponentButton = new JLabel("Repaint Component");
repaintComponentButton.setBorder(BorderFactory.createLineBorder(Color.BLACK));
repaintComponentButton.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
isRepaintComponent = true;
component.repaint();
}
});
southPane.add(repaintComponentButton);
JLabel repaintAllButton = new JLabel("Repaint all");
repaintAllButton.setBorder(BorderFactory.createLineBorder(Color.BLACK));
repaintAllButton.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
frame.repaint();
}
});
southPane.add(repaintAllButton);
contentPane.add(southPane, BorderLayout.SOUTH);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
---------- END SOURCE ----------
FREQUENCY : always