【发布时间】:2020-08-21 20:27:58
【问题描述】:
我知道 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);
}
}
【问题讨论】:
-
请阅读How do I ask a good question? 请注意上面写着的部分:帮助他人重现问题 如果您的问题与您的代码有关'已经写了,你应该包括一些。
-
我很高兴提供一些代码,但我认为这更像是 Java 的基础。让我看看是否可以在不提供图像的情况下创建一些显示问题的最小内容。
-
你在linux上吗?
-
我想我遇到了同样的问题,stackoverflow.com/questions/61188644/… 唯一能让它在没有任何跳跃的情况下持续重绘的方法是以更高的速率调用重绘。在 osx 上,我的示例非常顺利。在linux上它会开始跳跃。我不认为这是重绘的结合。
-
是的!我在Linux上!我刚开始怀疑它是否可能与硬件/操作系统有关!
标签: java swing repaintmanager