【问题标题】:Window freezes for one time when String is drawn绘制字符串时窗口冻结一次
【发布时间】:2015-07-30 22:21:48
【问题描述】:

当我用 Java 制作 2D 游戏时,发生了一个(至少对我而言)非常奇怪的问题。我提供了一个可运行的缩短示例,它重现了我的问题。当红色方块的x坐标100120之间时应该绘制字符串“示例文本“在广场上方。但是,如果运行代码,您会看到窗口完全冻结几秒钟。滞后后,您可以毫无问题地越过该区域,并且将显示文本。仅当程序在正方形上方绘制字符串时,才会出现此问题。如果我更改代码,只有另一个方块出现在红色方块上方,则没有延迟。 (我在我的代码中评论过)

任何帮助将不胜感激。

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JApplet;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;


public class MyExample extends JApplet {

    int x = 10;
    int y = 150;

    public void init() {

        setFocusable(true);
        requestFocus();
        Action right = new moveRight();
        Action left = new moveLeft();
        JRootPane rootPane = getRootPane();
        rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
        rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
        rootPane.getActionMap().put("right", right);
        rootPane.getActionMap().put("left", left);
        getContentPane().add(new Paint());
    }

    protected class moveRight extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            x+=3;
            repaint();
        }
    }
    protected class moveLeft extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            x-=3;
            repaint();
        }
    }

    class Paint extends JPanel {
        public void paintComponent(Graphics g) {  
            g.setColor(Color.RED);
            g.fillRect(x,y,10,10);
            g.setColor(Color.BLACK);
            g.drawLine(100,100,100,200);
            g.drawLine(129,100,129,200);
            if(x>100&&x<120) {
                g.setFont(new Font("TimesRoman", Font.PLAIN, 15));
                g.setColor(Color.BLACK);
                g.drawString("Sample Text",x-30,y-25);
                //g.fillRect(x,y-15,10,10); - This work fine if you remove the g.setFont and the drawString
            }
        }
    }

}

【问题讨论】:

  • 你有没有试过把它画到你的 if 之外?
  • 嗯,如果它在您的 if 之外使用完全相同的代码工作,而其他代码在您的“if”内工作,我想不出是什么导致问题触发
  • 很抱歉不能做很多事情,但我正在研究这个
  • 嗯,如果我读到的内容正确,请尝试将您的 if 更改为“if(x=100)”,这意味着程序会无限绘制
  • 啊,我的意思是它只是为了检查是否是触发错误的原因

标签: java swing graphics graphics2d


【解决方案1】:

这与您尝试在 paintComponent 方法中加载字体以及底层 API 尝试加载字体及其细节有关,然后才能绘制它们。

我确实认为您可以使用类似...的方式预先缓存字体

class Paint extends JPanel {

    private Font paintFont;

    public Paint() {
        paintFont = new Font("TimesRoman", Font.PLAIN, 15);
        setFont(paintFont);
    }

但在我的测试中,这仍然不起作用,我实际上最终做的是添加对getFontMetrics 的调用,这似乎强制 API 将字体及其属性加载到内存中,使其立即呈现,例如

class Paint extends JPanel {

    private Font paintFont;

    public Paint() {
        paintFont = new Font("TimesRoman", Font.PLAIN, 15);
        setFont(paintFont);
        getFontMetrics(paintFont);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.RED);
        g.fillRect(x, y, 10, 10);
        g.setColor(Color.BLACK);
        g.drawLine(100, 100, 100, 200);
        g.drawLine(129, 100, 129, 200);
        if (x > 100 && x < 120) {
            System.out.println("...");
            //g.setFont(paintFont);
            g.setColor(Color.BLACK);
            g.drawString("Sample Text", x - 30, y - 25);
            //g.fillRect(x,y-15,10,10); - This work fine if you remove the g.setFont and the drawString
        }
    }
}

现在,这将使您的应用程序加载速度稍微慢一些,但在您将字体加载移出绘制周期后,它会运行得更快

【讨论】:

    【解决方案2】:

    在我的系统上TimesRoman 不存在。

    我使用Times New Roman 没有问题。我还尝试了其他一些字体,它们都没有问题。所以我猜指定一个无效的字体名称会导致打嗝?

    我还创建了一次字体并缓存了它:

    Font font = new Font("Times New Roman", Font.PLAIN, 15);
    

    然后在画法中用到:

    g.setFont( font );
    

    另外,不要忘记super.paintComponent(g);

    这个问题包含我用来列出我机器上的字体的代码:Java JTextArea font

    【讨论】:

    • Just the caching mentioned in @camickr 's answer... - 实际上我的建议是使用正确的字体系列名称。你运行了我提供给你的字体程序吗? “TimesRoman”是否出现在字体列表中(它不适合我)?我必须承认我不知道这两种字体有什么区别。当我将两者并排打印时,它们对我来说看起来是一样的。所以我问你的问题是你怎么知道你得到的是“TimesRoman”而不是“Times New Roman”?所以我建议你使用 Java 知道的字体系列名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    • 2013-05-24
    • 2016-04-29
    • 2019-05-28
    • 2020-05-25
    • 2013-01-07
    相关资源
    最近更新 更多