Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当请求太快时,Swing组件(重新)绘制机制无法正确绘制_Java_Swing_Paint_Paintcomponent_Repaint - Fatal编程技术网

Java 当请求太快时,Swing组件(重新)绘制机制无法正确绘制

Java 当请求太快时,Swing组件(重新)绘制机制无法正确绘制,java,swing,paint,paintcomponent,repaint,Java,Swing,Paint,Paintcomponent,Repaint,从Java的文档中可以看出,组件的重绘机制经过了优化和缓存,因此即使多次调用,也不会阻塞绘图管道 似乎在非常繁重的调用下,有时它无法绘制最新的帧。考虑下面的例子: import java.awt.Graphics; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing

从Java的文档中可以看出,组件的重绘机制经过了优化和缓存,因此即使多次调用,也不会阻塞绘图管道

似乎在非常繁重的调用下,有时它无法绘制最新的帧。考虑下面的例子:

import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class TestRepaint extends JPanel {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setContentPane(new TestRepaint());
        frame.setSize(300, 100);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private long start;

    {
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                start = System.currentTimeMillis();
                System.out.println("Repaint");
                repaint();
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        long now = System.currentTimeMillis();
        int where = (int) ((now - start) / 5);
        if (where >= 200)
            g.drawString("DONE", 200, 30);
        else {
            g.drawString("Working...", where, 30);
            repaint();
        }
    }
}
当鼠标点击窗口时,“工作…”文本将向右滚动。在最后一帧,它应该变成“完成”。它似乎(随机)无法绘制最后一帧,而之前的“工作…”文本仍然保留。例如,如果我们强制重画显示(即更改窗口大小),则显示“完成”


看起来,由于重新绘制请求太快,组件的最后一次重新绘制失败。那么,有没有什么方法可以保证做到这一点

1)永远不要从绘制方法中调用
repaint()
——永远不要。2) 您应该覆盖paintComponent,而不是paint。3) 您应该在覆盖中调用super的方法。4) 阅读教程中解释的内容。通过在paint中调用
repaint()
,您将创建一个完全不可控且笨拙的动画,并可能会弄乱绘制链。如果你想要动画,用一种可以控制的方式来做,而不是有这个潜在的问题。每个方法都有一个特定的功能。绘画方法只适用于绘画。它不用于安排组件的绘制。Swing组件设计为在组件的属性更改时重新绘制自己。当您更改文本、字体、前景等时,组件将重新绘制自身。如果同时更改所有3个属性,则RepaitManager会将3个重新绘制请求合并为单个paint()请求。对于动画,您可以使用Swing定时器来安排重新绘制。为了进一步支持装满鳗鱼的气垫船和Camickr的评论,从
paint
方法中调用
repaint
,可以设置一个不受控制的更新过程,这将使EDT充满重新绘制请求,这将使其变得困难(或耗时)让它处理其他事件,并最终使CPU 100%运行。一个简单的解决方案是使用Swing
定时器
更新动画的状态,并定期安排一次
重新绘制
(例如,对于60fps为16毫秒),或者如果希望对帧速率进行更多控制,则安排一次
线程
,但这会带来更多的问题issues@Panayotis老实说,不要。Swing使用一个被动渲染引擎,它经过优化以这种方式工作,因此它不是为高频更新周期而设计的。Swing还可以将多个重绘请求减少为较少的重绘事件(这就是您可能遇到的情况)。相反,您需要尝试以足够小的间隔生成更新,以实现您的目标,但要足够大,以允许EDT时间呼吸和处理其他事件