我知道 Java RepaintManager 将合并对 repaint() 的调用,这对于 99% 的渲染来说都很好。我有一个 JPanel,我想在计时器(100 毫秒)上更新图像,以提供像视频一样的平滑渲染。在实践中,除非鼠标被移动,否则 RepaintManager 似乎会窃取/忽略所有其他 repaint() 。我想知道我必须有哪些选项来解决这个问题。我还查看了paintImmediately(),但它导致与repaint() 相同的行为,因此不是很有用。提前感谢您的有用想法!
- 是否可以为特定的 JPanel 创建和使用自定义 RepaintManager,并为其他所有内容使用默认值?
- 有没有办法让默认的 RepaintManger 确定某个面板是“脏的”,这样它会被重新绘制而不是被忽略?
下面是一些用于说明实现的代码,您会注意到(至少在我的 Linux 测试中),这些数字几乎会跳过所有其他序列。
public class PanelRepaintIssue
{
private static final int kWIDTH = 200;
private static final int kHEIGHT = 100;
private static final int kNUM_IMAGES = 10;
private static final int kREPAINT_DELAY = 250;
private final JPanel _ImagePanel;
private final BufferedImage[] _Images;
private final Timer _Timer;
private TimerTask _TimerTask;
private int _Index;
public PanelRepaintIssue()
{
_Index = 0;
_ImagePanel = new JPanel()
{
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if (_Index < kNUM_IMAGES)
{
g.drawImage(_Images[_Index], 0, 0, null);
}
}
};
_ImagePanel.setSize(new Dimension(kWIDTH, kHEIGHT));
_ImagePanel.setPreferredSize(new Dimension(kWIDTH, kHEIGHT));
_Images = new BufferedImage[kNUM_IMAGES];
for (int i = 0; i < _Images.length; ++i)
{
_Images[i] = new BufferedImage(kWIDTH, kHEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D t2d = _Images[i].createGraphics();
t2d.setColor(Color.BLACK);
t2d.fillRect(0, 0, kWIDTH, kHEIGHT);
t2d.setColor(Color.RED);
t2d.drawString(Integer.toString(i), kWIDTH/2, kHEIGHT/2);
t2d.dispose();
}
_Timer = new Timer(this.getClass().getName());
}
public JPanel getPanel()
{
return _ImagePanel;
}
public void start()
{
if (null != _TimerTask)
{
_TimerTask.cancel();
_TimerTask = null;
}
_TimerTask = new TimerTask()
{
@Override
public void run()
{
++_Index;
if (_Index >= kNUM_IMAGES)
{
_Index = 0;
}
_ImagePanel.repaint();
// Also tried _ImagePanel.paintImmediately(0, 0, kWIDTH, kHEIGHT);
}
};
_Timer.scheduleAtFixedRate(_TimerTask, 1000, kREPAINT_DELAY);
}
public static void main(String[] args)
{
PanelRepaintIssue tPanel = new PanelRepaintIssue();
tPanel.start();
JFrame tFrame = new JFrame("PanelRepaintIssue");
tFrame.add(tPanel.getPanel());
tFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tFrame.setResizable(false);
tFrame.pack();
tFrame.setVisible(true);
}
}