java - 大型 JPanel 上的绘制字符串在 Linux 上变得困惑,但在 Windows 上却不然

标签 java swing graphics java-2d

我在 Graphics drawString 方法上遇到了问题。简而言之,我观察到 Linux 上 drawString 的意外行为,如果面板尺寸很大,字符串会变得困惑。

举个例子。我修改了 Oracle 中的 ScrollDemo2 类以在 drawingPane 上绘制字符串:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class ScrollDemo2 extends JPanel
                          {
    private Dimension area; 
    private JPanel drawingPane;

    public ScrollDemo2() {
        super(new BorderLayout());

        area = new Dimension(100000,1000);

        drawingPane = new DrawingPane();
        drawingPane.setBackground(Color.white);
        drawingPane.setPreferredSize(area);
        drawingPane.revalidate();
        drawingPane.repaint();

        JScrollPane scroller = new JScrollPane(drawingPane);
        scroller.setPreferredSize(new Dimension(500,500));

        add(scroller, BorderLayout.CENTER);
    }

    public class DrawingPane extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // drawString gives correct results in Windows but gives messy strings in Linux; drawLine gives correct lines in both Windows and Linux
            for (int i = 0; i < 100000; i += 100)
                g.drawString("Mark " + i, i, 20);
            for (int i = 0; i < 100000; i += 100)
                g.drawLine(i, i % 1000 / 10 + 25, i, i % 1000 / 10 + 35);

        }

    }


    private static void createAndShowGUI() {
        JFrame frame = new JFrame("ScrollDemo2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JComponent newContentPane = new ScrollDemo2();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

程序在 Windows 7 上运行

程序在 Windows 7 上显示正确的字符串。

程序在Linux 14.04上运行

该程序在 Linux 上显示困惑的字符串。

除了drawString方法之外,还添加了drawLine方法,并且drawLine方法在Windows和Linux下都可以正常工作。

这是为什么呢?在Linux上应该如何重写代码来解决这个问题?

最佳答案

如评论中所述,如果绘制静态(稳定不变的背景图像),请使用 BufferedImage。例如:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class ScrollDemo2B extends JPanel
                          {
    private static final int IMG_W = 100000;
    private static final int IMG_H = 1000;
    // private Dimension area; 
    private JPanel drawingPane;
    private BufferedImage img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);

    public ScrollDemo2B() {
        super(new BorderLayout());

        Graphics2D g2 = img.createGraphics();
        g2.setColor(Color.BLACK);
        for (int i = 0; i < 100000; i += 100) {
            g2.drawString("Mark " + i, i, 20);
        }
        for (int i = 0; i < 100000; i += 100) {
            g2.drawLine(i, i % 1000 / 10 + 25, i, i % 1000 / 10 + 35);
        }
        g2.dispose();

        drawingPane = new DrawingPane();
        drawingPane.setBackground(Color.white);
        drawingPane.revalidate();
        drawingPane.repaint();

        JScrollPane scroller = new JScrollPane(drawingPane);
        scroller.setPreferredSize(new Dimension(500,500));

        add(scroller, BorderLayout.CENTER);
    }

    public class DrawingPane extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (img != null) {
                g.drawImage(img, 0, 0, this);
            }
        }

        @Override
        public Dimension getPreferredSize() {
            if (isPreferredSizeSet() || img == null) {
                return super.getPreferredSize();
            }
            int w = img.getWidth();
            int h = img.getHeight();
            return new Dimension(w, h);
        }

    }


    private static void createAndShowGUI() {
        JFrame frame = new JFrame("ScrollDemo2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JComponent newContentPane = new ScrollDemo2B();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

然后,如果您有移动 Sprite 或动态图像,您可以在paintComponent方法中绘制它们。

关于java - 大型 JPanel 上的绘制字符串在 Linux 上变得困惑,但在 Windows 上却不然,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44394681/

相关文章:

java - 增加 Swing 中标题栏的大小

Java向JOptionPane添加组件

c++ - 使用 floodfill c++ 填充矩形

java - LWJGL (Java) 中 OpenGL 的奇怪光照行为

java - cucumber 4 可选单词?

Java Spring STOMP MessageMapping 未被调用

java - 尝试打开 asset/database.db 时出错

java - ClassCastException : javax. swing.plaf.FontUIResource 无法转换为 javax.swing.InputMap

java - 无返回类型的错误

graphics - Corona 中所有设备的背景图像大小