为什么这个JLabel不断重新粉刷?

时间:2010-05-07 20:08:23

标签: java swing paint

我有一个项目,当它存在时似乎不断重绘,导致CPU在任何窗口中出现尖峰。它直接继承自JLabel,与屏幕上的其他JLabel不同,它具有红色背景和边框。我不知道为什么它会不同于连续重绘。 callstack看起来像这样:

Thread [AWT-EventQueue-1] (Suspended (breakpoint at line 260 in sItem)) 
    sItem.paint(Graphics) line: 260 
    sItem(JComponent).paintToOffscreen(Graphics, int, int, int, int, int, int) line: 5124   
    RepaintManager$PaintManager.paintDoubleBuffered(JComponent, Image, Graphics, int, int, int, int) line: 1475 
    RepaintManager$PaintManager.paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1406  
    RepaintManager.paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1220   
    sItem(JComponent)._paintImmediately(int, int, int, int) line: 5072  
    sItem(JComponent).paintImmediately(int, int, int, int) line: 4882   
    RepaintManager.paintDirtyRegions(Map<Component,Rectangle>) line: 803    
    RepaintManager.paintDirtyRegions() line: 714    
    RepaintManager.seqPaintDirtyRegions() line: 694 [local variables unavailable]   
    SystemEventQueueUtilities$ComponentWorkRequest.run() line: 128  
    InvocationEvent.dispatch() line: 209    
    summitEventQueue(EventQueue).dispatchEvent(AWTEvent) line: 597  
    summitEventQueue(SummitHackableEventQueue).dispatchEvent(AWTEvent) line: 26 
    summitEventQueue.dispatchEvent(AWTEvent) line: 62   
    EventDispatchThread.pumpOneEventForFilters(int) line: 269   
    EventDispatchThread.pumpEventsForFilter(int, Conditional, EventFilter) line: 184    
    EventDispatchThread.pumpEventsForHierarchy(int, Conditional, Component) line: 174   
    EventDispatchThread.pumpEvents(int, Conditional) line: 169  
    EventDispatchThread.pumpEvents(Conditional) line: 161   
    EventDispatchThread.run() line: 122 [local variables unavailable]   

它基本上只是一次又一次地连续击中,尽可能快地按下继续。对此特定标签“唯一”的代码大致如下所示:

bgColor = OurColors.clrWindowTextAlert;
textColor = Color.white;
setBackground(bgColor);
setOpaque(true);
setSize(150, getHeight());
Border border_warning = BorderFactory.createCompoundBorder(
        BorderFactory.createMatteBorder(1, 1, 1, 1, OurColors.clrXBoxBorder),
        Global.border_left_margin);
setBorder(border_warning);

它显然做得更多,但这个特殊的块只存在于导致尖峰/连续重绘的这些标签上。

为什么它会不断重新绘制这个特定的标签?

3 个答案:

答案 0 :(得分:4)

很多代码遗失了,但我会接受一个有根据的猜测。

该类的“唯一”部分可能位于负责呈现Label的代码的一部分内。如果这是真的,那么调用所有这些setXXX()方法可能会使对象变脏,这意味着它需要重新绘制,这将再次进入此代码块,然后将使用公共接口更新小部件,然后使对象变脏,导致循环重复。

最终这样的事情会占用所有备用周期,导致CPU最大化一个显然没有做太多的标签。

尝试在渲染循环外部的位置设置适当的值。大多数这些项看起来都可以在构造函数中设置。

---确认后编辑它是setBorder(...)---

设置新边框可能会触发重新计算窗口小部件的边界框,因为边框可能比前一个边框更大或更小。那个和新的边框可能包含与旧的边框不同的屏幕显示(提升,降低等)。

这些项目都不需要在渲染部分设置,但我敢打赌,对于其他项目,会进行一次检查以查看新项目equals(...)是否为旧项目。如果是这样,则(作为优化)不设置脏位,并且不会对渲染引擎进行刷新请求。

使用边框,这样的检查必须涵盖几个元素,包括一些编译的字节码(实际的绘图指令)。由于在考虑边界时检查相等性不再是简单的优化,因此它们不会尝试检查相等性,只是标记窗口小部件以进行重新绘制。

答案 1 :(得分:2)

请参阅JComponent.setBorder()中的代码。它使用简单的比较来比较旧边框和新边框 - 它总是返回false,因为它们是两个不同的对象。如果条件成立,则组件将重新绘制。因此无限循环。

作为一般规则 - 在其paint方法中调用组件上的任何setter。正如您所看到的,设置边框将导致无限重绘循环。任何其他设置都可能发生这种情况,如果不是在此版本的VM中,则可能在下一个设置中。正确的方法是在模型更改时更改组件(视图)的属性,让Swing在重新绘制时找出它 - 或者自己调用repaint()。

答案 2 :(得分:0)

这是边界。在每个绘制循环期间创建边框一些如何使其连续重绘。如果我只创建一次作为类作用域私有对象的边框并将其设置在绘制循环中,它会正确设置边框并且不会连续重绘。如果有人知道为什么会产生影响,我也会很感激这些信息。请随意对此发表评论,我会接受我的答案,或者添加一个带有大量冗长的新答案,我会接受你的答案。