Java 绘制字符串时,窗口冻结一次

Java 绘制字符串时,窗口冻结一次,java,swing,graphics,graphics2d,Java,Swing,Graphics,Graphics2d,当我用Java制作2D游戏时,发生了一个(至少对我来说)非常奇怪的问题。我提供了一个可运行、简短的示例,它再现了我的问题。当红方块的x坐标介于100和120之间时,应在方块上方绘制字符串“示例文本”。但是,您将看到,如果运行代码,窗口将完全冻结几秒钟。延迟后,您可以毫无问题地浏览该区域,并显示文本。只有当程序在正方形上方绘制字符串时,才会出现此问题。如果我更改代码,使红色方块上方只出现另一个方块,则没有延迟。(我在代码中对此进行了注释) 任何帮助都将不胜感激 import java.awt.Co

当我用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
            }
        }
    }

}
导入java.awt.Color;
导入java.awt.Font;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.KeyEvent;
导入javax.swing.AbstractAction;
导入javax.swing.Action;
导入javax.swing.JApplet;
导入javax.swing.JComponent;
导入javax.swing.JPanel;
导入javax.swing.JRootPane;
导入javax.swing.KeyStroke;
公共类MyExample扩展了JApplet{
int x=10;
int y=150;
公共void init(){
设置聚焦(真);
requestFocus();
Action right=新的moveRight();
Action left=新的moveLeft();
JRootPane rootPane=getRootPane();
getInputMap(JComponent.WHEN_在聚焦窗口中)。put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),“RIGHT”);
getInputMap(JComponent.WHEN_在聚焦窗口中)。put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),“LEFT”);
getActionMap().put(“右”,右);
getActionMap().put(“左”,左);
getContentPane().add(新绘制());
}
受保护的类moveRight扩展了AbstractAction{
已执行的公共无效操作(操作事件e){
x+=3;
重新油漆();
}
}
受保护的类moveLeft扩展了AbstractAction{
已执行的公共无效操作(操作事件e){
x-=3;
重新油漆();
}
}
类Paint扩展了JPanel{
公共组件(图形g){
g、 setColor(Color.RED);
g、 fillRect(x,y,10,10);
g、 设置颜色(颜色为黑色);
g、 抽绳(100200);
g、 抽绳(129100129200);

如果(x>100&&x这与您试图在
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
        }
    }
}
class Paint扩展了JPanel{
私有字体;
公共油漆(){
paintFont=新字体(“TimeRoman”,Font.PLAIN,15);
setFont(paintFont);
getFontMetrics(paintFont);
}
@凌驾
公共组件(图形g){
超级组件(g);
g、 setColor(Color.RED);
g、 fillRect(x,y,10,10);
g、 设置颜色(颜色为黑色);
g、 抽绳(100100200);
g、 抽绳(129100129200);
如果(x>100&&x<120){
System.out.println(“…”);
//g、 setFont(paintFont);
g、 设置颜色(颜色为黑色);
g、 抽绳(“样本文本”,x-30,y-25);
//g、 fillRect(x,y-15,10,10);-如果删除g.setFont和抽绳,这项工作很好
}
}
}

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

我使用的是《泰晤士报新罗马版》
,没有问题。我还尝试了一些其他字体,它们都没有问题。所以我猜指定无效的字体名称会导致打嗝

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

Font font = new Font("Times New Roman", Font.PLAIN, 15);
然后在使用的绘画方法中:

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


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

你是否尝试在if之外绘制它?嗯,如果它在if之外使用完全相同的代码工作,而其他代码在if内部工作我想不出是什么原因导致了问题的触发对不起,我不能做很多事情,但我正在对此进行研究。嗯,试着把你的if改为“if(x=100)”如果我读到的是正确的,这意味着该程序一直在无限地绘制。是的,我的意思是作为一个测试,只是为了检查这是否是触发错误的原因。
只是@camickr的答案中提到的缓存…
-实际上我的建议是使用正确的字体系列名称。你运行了我提供给你的字体程序吗?是“TimeRoman”吗出现在字体列表中(对我来说不是)?我必须承认我不知道这两种字体之间有什么区别。当我并排打印这两种字体时,它们看起来是一样的。所以我想问你的问题是,你怎么知道你得到的是“TimeRoman”而不是“Times New Roman”?所以我建议你使用Java知道的字体家族名称。