【问题标题】:HiDPI support with java 9+, scalling issue with JTable gridlines with Windows L&F - but not Nimbusjava 9+ 的 HiDPI 支持,Windows L&F 的 JTable 网格线的缩放问题 - 但不包括 Nimbus
【发布时间】:2019-05-05 09:12:37
【问题描述】:

我正在将我的 Swing 应用程序迁移到 Java 11 以利用 HiDPI 显示支持。我使用的是三星显示器,分辨率设置为 3840x2160,缩放比例为 125%,Windows 10。

虽然 java 9 及更高版本被宣传为可以正确处理 HiDPI 缩放,但在显示简单的 JTable 时,网格线会出现不同的粗细,如下所示:

下面是代码:

import javax.swing.*;

public class TestTable {
    public static void main(String[] args) {
        new TestTable();
    }

    public TestTable() {
        JTable table = new JTable(12,6);

        JDialog dialog = new JDialog();
        JScrollPane sp = new JScrollPane(table);

        table.setShowGrid(true);
        table.setRowHeight(25);

        dialog.setContentPane(sp);
        dialog.setSize(300,300);
        dialog.setVisible(true);
        dialog.setLocationRelativeTo(null);
    }
}

但是,当设置 Nimbus L&F 时,问题就消失了:

import javax.swing.*;

public class TestTable {
    public static void main(String[] args) {
        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) { }

        new TestTable();
    }

    public TestTable() {
        JTable table = new JTable(12,6);

        JDialog dialog = new JDialog();
        JScrollPane sp = new JScrollPane(table);

        table.setShowGrid(true);
        table.setRowHeight(25);

        dialog.setContentPane(sp);
        dialog.setSize(300,300);
        dialog.setVisible(true);
        dialog.setLocationRelativeTo(null);
    }
}

如何使用默认的 Windows L&F 实现相同的功能?

(使用 java 9 和 10 观察到相同的行为)

【问题讨论】:

    标签: java look-and-feel nimbus hidpi


    【解决方案1】:

    区别在于两者的外观和感觉如何渲染它们的网格线。

    默认外观MetalLookAndFeel(和WindowsLookAndFeel)基于BasicLookAndFeel,它使用BasicTableUI 类来呈现JTable。在 BasicTableUI.paintGrid() 中,它调用了诸如 SwingUtilities2.drawHLine() 之类的东西——实际上它调用了 Graphics.fillRect(),这就是问题所在。

    Nimbus 外观使用 SynthTableUI 类。在SynthTableUI.paintGrid() 中,它最终确实调用了Graphics.drawLine(),这清楚地在缩放下绘制了一条更清晰的线。

    正如您所说,这听起来像是 HiDPI 下的主要外观和感觉中的一个错误。


    可以为此创建一个解决方法,尽管它不是特别优雅。

    使用正在使用的Graphics 的自定义版本,如果宽度或高度为1,则可以覆盖fillRect() 以使用drawLine()。此自定义Graphics 可以在绘画时专门引入表:

        JTable table = new JTable(12, 6) {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(new GraphicsWorkaround(g));
            }
        };
    

    (匿名子类只是为了简洁起见)。

    然后GraphicsWorkaround 类被编写为传入的真正g 的包装器。这里的子类化DebugGraphics 只是避免在Graphics 中的所有其他方法中编写委托调用的技巧:

    import java.awt.Graphics;
    import javax.swing.DebugGraphics;
    
    public class GraphicsWorkaround extends DebugGraphics {
        private final Graphics g;
    
        public GraphicsWorkaround(Graphics g) {
            super(g);
            this.g = g;
        }
    
        @Override
        public Graphics create() {
            return new GraphicsWorkaround(g.create());
        }
    
        @Override
        public void fillRect(int x, int y, int width, int height) {
            if (width == 1)
                g.drawLine(x, y, x, y + height - 1);
            else if (height == 1)
                g.drawLine(x, y, x + width - 1, y);
            else
                super.fillRect(x, y, width, height);
        }
    }
    

    create() 方法用于处理在JComponent.paintComponent() 中创建的内部scratchGraphics 克隆)。

    这使得 drawLine() 能够被调用,这在 125% 缩放时看起来要好得多。

    【讨论】:

    • 谢谢,我会接受这个答案,因为它清楚地解释了这种行为的根本原因,并提出了一个好的解决方法。然而,它在我的最后产生了一些其他问题(在扩展原始示例时),与字体和颜色有关,但我相信我可以找到这些问题的解决方案。我想我会报告这个行为(错误?),看看会发生什么。
    猜你喜欢
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多