JEditorPane и масштаб шрифта

У меня есть область Graphics2D, где я рисую геометрические примитивы. Его можно легко масштабировать с помощью g2.scale(x, y). Теперь я хочу нарисовать текст в моей масштабируемой области и отредактировать текст прямо в ней. Это тоже работает, но, к сожалению, есть одна проблема, которую можно проиллюстрировать. Вот так это выглядит на мониторе на 100%: введите здесь описание изображения

И вот что происходит на 300%:

введите здесь описание изображения

Положение буквы "А" почти нормальное, а положение буквы В скачет влево-вправо. Я предполагаю, что JEditorPane просто берет ближайший шрифт для отображения масштабированного шрифта. И пространство в разных шрифтах может иметь немного разный размер в пикселях. То есть в начале строки проблем не возникает, но в конце накапливается ошибка.

Как я могу добиться того, чтобы JEditorPane отображал шрифт в одних и тех же позициях при любом g2.scale()? (Например, OpenOffice работает корректно с той же проблемой).

UPD: sscce

class Canvas extends JPanel {
    @Override
    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g.translate(p.x, p.y);
        g2.scale(scale, scale);
        g2.setColor(Color.GRAY);
        g2.fill(g2.getClip());

        JEditorPane pane = new JEditorPane();
        pane.setFont(pane.getFont().deriveFont(22f));
        pane.setText("A                                                                                              B");
        pane.setBounds(new Rectangle(100, 100, 700, 30));
        g2.translate(100, 100);
        pane.paint(g2);
        g2.translate(-100, -100);

        g2.setColor(Color.BLACK);
        g2.draw(new Rectangle(100, 100, 700, 30));


        g2.scale(1 / scale, 1 / scale);
        g.translate(-p.x, -p.y);
        g2.setColor(Color.GREEN);
        g2.setFont(g2.getFont().deriveFont(33f));
        g2.drawString("Scale (mouse wheel): " + new DecimalFormat("#.##").format(scale * 100) + "%", 2, 768-66);
        g2.drawString("(Drag mouse to move)", 2, 768-33);
    }


// +++++++++++++++++++++++++++ GUI +++++++++++++++++++++++++++++++++++++

    public Canvas() {
        addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                scale += e.getWheelRotation() * 1.0 / 10;
                repaint();
            }
        });

        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                p.x = e.getPoint().x - startDrag.x;
                p.y = e.getPoint().y - startDrag.y;
                repaint();
            }
        });

        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                startDrag = e.getPoint();
                startDrag.x -= p.x;
                startDrag.y -= p.y;
            }
        });
    }

    public static double scale = 1.0;
    public static Point p = new Point();
    public static Point startDrag = new Point();
}

public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(new Canvas());

        frame.setSize(1024, 768);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

person AvrDragon    schedule 02.11.2012    source источник
comment
Измените свой вопрос, включив в него sscce, который указывает на описанную вами проблему.   -  person trashgod    schedule 02.11.2012
comment
См. также этот TextLayout пример.   -  person trashgod    schedule 02.11.2012


Ответы (2)


См. там http://java-sl.com/articles.html статьи о масштабировании JEditorPane. В статье «Масштабирование с помощью пользовательского GlyphPainter и поддержки дробных размеров» объясняется проблема масштабирования и измерения шрифта. Вы можете использовать рисование на основе TextLayout или GlyphVector, чтобы исправить дробное измерение fnt.

person StanislavL    schedule 02.11.2012
comment
› GlyphPainter1 (к сожалению, он не общедоступный) GlyphPainter1 все еще не является общедоступным? - person AvrDragon; 02.11.2012
comment
Вы можете написать свой GlyphPainter или использовать описанный во второй статье. - person StanislavL; 02.11.2012

Я боролся с тем же самым в течение некоторого времени. Проблема усугубляется, когда вы пытаетесь выровнять текст по правому краю и использовать небольшой размер шрифта (отсюда много символов в строке). Масштабирование просто умножает ошибки и делает их легко видимыми.

Использование упомянутой выше статьи и кода «Масштабирование с помощью пользовательского GlyphPainter и поддержки дробных измерений» поможет, поскольку переключение с int на float избавляет от ошибки округления. Работает почти нормально, но не совсем, т.е. там что-то еще происходит.

В ScaledGlyphPainter.getTabbedTextWidth я заменил фактический размер

nextX += metrics.getStringBounds(txtStr, n - charCount, n, painterGr).getWidth();

С участием

FontRenderContext  frc = new FontRenderContext(new AffineTransform (), true, true);
TextLayout layout = new TextLayout (text, metrics.getFont(), frc);
nextX += layout.getBounds().getWidth();

Судя по всему, оба измерения дадут разные результаты по одному и тому же тексту!!!! Если измерение происходит одним способом, а рисование другим, вы получите ошибки рисования. Как только я изменил приведенный выше код, чтобы использовать измерение TextLayout, все проблемы исчезли, и выравнивание работает по мере необходимости.

person Yishai Steinhart    schedule 21.03.2013