Swing HiDPI 边框渲染 (Windows 10/OpenJRE 11)

Swing HiDPI Border rendering (Windows 10/OpenJRE 11)

我维护一个使用自定义 border implementations as window decorations with a look and feel implementation which extends MetalLookAndFeel 的旧 Swing 应用程序。 look and feel 覆盖 initComponentDefaults(UIDefaults table) 并将自定义边框安装为 "RootPane.frameBorder" 等等。

自定义边框本身通过实现 paintBorder(Component c, Graphics g, int x, int y, int width, int height) 水平绘制 32 行预定义颜色。当 display scalingSettings > Display > Scale and layout 中设置为 100% 时,这适用于 Windows 10 2004 或更新版本。当display scaling设置为125%或以上时,边框将无法正确绘制,应该绘制在一起的线条之间有白线。

Fix scaling for apps in Advanced scaling settings 貌似不影响边框绘制。

我用AdoptOpenJDK OpenJDK 11.0.4+11 x64。我希望 Swing 也能按比例放大线条,比如字体等。

为什么会这样?这可能如何解决?

边框实现:

public class CustomWindowBorder implements Border{

   public static final int BORDER_THICKNESS = 3;
   
   private static final CustomWindowBorder globalInstance = new CustomWindowBorder();

   public static CustomWindowBorder getInstance(){

      return CustomWindowBorder.globalInstance;
   }

   private CustomWindowBorder(){}
   
   @Override
   public Insets getBorderInsets(Component c){

      return new Insets(1,
                        CustomWindowBorder.BORDER_THICKNESS,
                        CustomWindowBorder.BORDER_THICKNESS,
                        CustomWindowBorder.BORDER_THICKNESS);
   }

   @Override
   public boolean isBorderOpaque(){

      return true;
   }

   @Override
   public void paintBorder(Component c,
                           Graphics g,
                           int x,
                           int y,
                           int width,
                           int height){

      Color[] decorationColors = [ommited]; // 30 colors in total
      Color[] borderColors = [ommited]; // 3 colors in total

      int yStart = 30;

      for(int i = 0; i < decorationColors.length; i++ ){
         // top
         Color clr = decorationColors[i];
         g.setColor(clr);

         g.drawLine(0,
                    i,
                    width,
                    i);
      }

      for(int i = 0; i < borderColors.length; i++ ){
         Color clr = borderColors[i];
         g.setColor(clr);

         // left
         g.drawLine(i,
                    yStart,
                    i,
                    height - i - 1);
         // right
         g.drawLine(width - i - 1,
                    yStart,
                    width - i - 1,
                    height - i - 1);
         // below
         g.drawLine(i,
                    height - i - 1,
                    width - i - 1,
                    height - i - 1);
      }
   }
}

我发现当使用具有一个像素宽度或高度的 Graphics::drawLineGraphics::fillRect 时,Swing 在屏幕上恰好绘制了一个未缩放的像素宽线,独立于 Windows' s 显示缩放。

当我用Graphics::fillRect画边框,让它填满顶部的每30条水平线和另一边的3条线,白色的space就会被填满。

我的解决方案是在 Graphics::fillRect 上绘制每条线,然后用颜色填充剩余的所有线,减少填充矩形的 width/height,同时将其移动到下一行。这不是最有效的绘制方法,但对我有用。

修改的paintBorder方法:

@Override
public void paintBorder(Component c,
                        Graphics g,
                        int x,
                        int y,
                        int width,
                        int height){

   Color[] decorationColors = [ommited]; // 30 colors in total
   Color[] borderColors = [ommited]; // 3 colors in total

   int yStart = 30;

   for(int i = 0; i < decorationColors.length; i++ ){
      // top
      Color clr = decorationColors[i];
      g.setColor(clr);

      g.fillRect(0,
                 i,
                 width,
                 decorationColors.length - i);
   }

   for(int i = 0; i < borderColors.length; i++ ){
      Color clr = borderColors ;
      g.setColor(clr);

      // left
      g.fillRect(i,
                 yStart,
                 borderColors.length - i,
                 height - yStart - i);

   }
   for(int i = borderColors.length - 1; i >= 0; i-- ){
      Color clr = borderColors[i];
      g.setColor(clr);

      // right
      g.fillRect(width - i - 1,
                 yStart,
                 borderColors.length - i,
                 height - yStart - i);
      // below
      g.fillRect(i,
                 height - i - 1,
                 width - i,
                 borderColors.length - i);
   }
}