Поддержка HiDPI с java 9+, устранение проблемы с линиями сетки JTable с Windows L & F - но не с Nimbus - PullRequest
0 голосов
/ 04 декабря 2018

Я перевожу свое приложение Swing на Java 11, чтобы воспользоваться поддержкой отображения HiDPI.Я использую монитор Samsung с разрешением 3840x2160, с масштабированием 125%, с Windows 10.

Несмотря на то, что Java 9 и выше объявлены как правильно обрабатывающие HiDPI масштабирование, при отображении простой JTable появляются линии сеткиразной толщины, как показано здесь:

JTable gridlines issue

Вот код для этого:

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);
    }
}

Однако при настройке NimbusL & F, проблема исчезает:

JTable Nimbus

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)

1 Ответ

0 голосов
/ 07 декабря 2018

Разница в том, как эти двое выглядят и чувствуют свои линии сетки.

Внешний вид и ощущение по умолчанию MetalLookAndFeelWindowsLookAndFeel) основаны на BasicLookAndFeel, который использует BasicTableUIкласс для отображения JTable BasicTableUI.paintGrid () он вызывает, например, SwingUtilities2.drawHLine () - что на самом деле вызывает Graphics.fillRect(), что является проблемой.

Внешний вид Nimbusиспользует класс SynthTableUI.В SynthTableUI.paintGrid () он в конечном счете вызывает Graphics.drawLine(), который четко рисует более чистую линию при масштабировании.

Как вы говорите, это звучит как ошибка в основном виде и чувствуетпод HiDPI.


Для этого можно создать обходной путь, хотя это не особенно элегантно.

При использовании настраиваемой версии Graphics, которая используется, возможнопереопределить fillRect() для использования drawLine() вместо этого, если ширина или высота равна 1. Этот пользовательский 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() для обработки внутреннего клона scratchGraphics, созданного в JComponent.paintComponent()).

Затем включается drawLine() называться после всего, что выгляделонамного лучше при масштабировании 125%.

...