我在JScrollPane中放置了一个JPanel对象,滚动按预期工作。通过覆盖paintComponent(),我试图在JPanel对象中进行自定义绘制。但是,当JPanel对象放在JScrollPane中时,JPanel不再正确绘制(而只显示其背景颜色)。
因为我的应用程序要求不断更新JPanel,所以构造一个单独的线程以特定间隔重新绘制JPanel。
以下代码摘录显示了我当前的项目:
a)来自我的JPanel的paintComponent()(此方法已被裁减为仅绘画,实际绘制将是从另一个线程而不是这个大粉红色静态框提供的不断更新的BufferedImage):
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
//Render Frame
// 'RXDisplayCanvas' is the JPanel.
Graphics2D G2D = (Graphics2D)RXDisplayCanvas.getGraphics();
G2D.setColor(Color.PINK);
//800 and 600 are arbitrary values for this example, real values are calculated at runtime. The value calculation code is verified to work (as its used elsewhere in a similar scenario)
G2D.fillRect(0, 0, 800, 600);
G2D.dispose();
}
b)定期重新绘制帧的'updater'线程:
@Override
public void run() {
long MaxFrameTime;
long Time;
while(isVisible()){
// 'FPSLimit' is a integer value (default to 30)
MaxFrameTime = Math.round(1000000000.0 / FPSLimit);
Time = System.nanoTime();
try{
SwingUtilities.invokeAndWait(new Runnable(){
@Override
public void run() {
// 'RXDisplayCanvas' is the JPanel.
RXDisplayCanvas.repaint(); //When using this, the JPanel does not display correctly.
//RXDisplayCanvas.paintImmediately(0, 0, RXDisplayCanvas.getWidth(), RXDisplayCanvas.getHeight()); When using this, the JPanel renders correctly but flickers.
}
});
}catch(InterruptedException | InvocationTargetException e){}
Time = System.nanoTime() - Time;
if(Time < MaxFrameTime){
try{
Thread.sleep(Math.round((MaxFrameTime - Time)/1000000.0));
}catch(InterruptedException ex){}
}
}
}
我已经考虑到repaint()不会立即重新绘制屏幕,但问题在于屏幕呈现错误。当程序保持不变时,它只渲染JPanel的背景颜色,直到滚动JScrollPane,在下一次repaint()调用绘制错误显示之前,它正确渲染一帧。
当为paintImmediately()(在摘录b中)切换repaint()时,框架正确渲染但存在大量闪烁,其中它在绘制背景颜色和绘制粉红色框之间不断交替。我尝试添加和删除布局管理器,禁用重绘管理器以及启用和禁用两个组件的“双缓冲”标志,其中所有组件都导致上述两种行为之一(仅渲染背景或闪烁)。
有人可以帮我解决这个问题吗?
N.B:我很清楚Java的变量命名约定,因为这是一个私有项目,我选择用大写字母开始变量名,因为我觉得它看起来更好,请不要发表评论。
答案 0 :(得分:7)
1)我不确定:
public void paintComponent(Graphics g){
super.paintComponent(g);
// 'RXDisplayCanvas' is the JPanel.
Graphics2D G2D = (Graphics2D)RXDisplayCanvas.getGraphics();
..
G2D.dispose();
}
我建议你这样做:
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D G2D = (Graphics2D)g;
G2D.setColor(Color.PINK);
G2D.fillRect(0, 0, 800, 600);
}
请注意我如何省略getGraphics
,并使用paintComponent
图形上下文中传递的当前值。
另请注意,我不会致电g2d.dipose()
,因为这会导致问题,只应在您创建Graphic
的{{1}}上进行,但在您的情况下,您甚至不应该创建已创建Component.getGraphics()
上下文,并将其传递给paintComponent方法。 (见this类似问题)
2)Graphic
不需要SwingUtilities.invokeXXX
阻止,因为它是线程安全的。但特别是不需要repaint()
(因为这是一个阻塞调用并等待所有待处理的AWT事件被处理并且run()方法完成)这不好并且还可能添加到您看到的屏幕上的视觉文物。
3)我尝试添加和删除布局管理器,禁用重绘管理器以及启用和禁用两个组件的'double buffered'标志,其中所有组件都导致上述两种行为之一(仅渲染)背景或闪烁)。撤消所有这些,因为我无法看到它是如何影响绘画的。
如果我有SSCCE来说明不需要的行为,那会更有帮助。因为我可以尝试重现您的错误,但我很可能无法(由于适用于您的应用的特定条件可能会导致这些视觉文物)