Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6670649
Votes 0
Synopsis Swing JFrames don't get repainted once shown if JFrame.repaint() is called
Category java:classes_awt
Reported Against
Release Fixed 6u10(b14)
State 10-Fix Delivered, Verified, bug
Priority: 2-High
Related Bugs
Submit Date 03-MAR-2008
Description
Run the attached test:
  java -Dusenonop -Duseswing TSFrame
Or run 
  java TranslucentShapedFrameTest
and check non-opaque, 'use JFrame', and "create Frame"

You'll see that the JFrame that appears doesn't animate
as it's supposed to.

The paintComponent method is getting called.
Posted Date : 2008-03-03 23:41:20.0
Work Around
The workaround here is to call jpanel.repaint() instead
of jframe.repaint(). (Note that a repaint of a single
component will cause a repaint of the whole frame anyway)

While this is a sufficient workaround for small apps it's
difficult to implmeent in scenario's code.
Evaluation
Animating non-opaque JFrames doesn't work in some cases.

My example has JFrame with a (non-opaque, non-double-buffered) JPanel.

If a jframe.repaint() is called instead of
jpanel.repaint(), we eventually end up in
RepaintManager.paintDirtyRegions, which calls updateWindows().
There we iterate through the dirty components, find their
Window ancestors and call updateWindow on them.

The problem is that if the dirty component _is_ a JFrame, then
SwingUtilities.getWindowAncestor() returns null because
it doesn't expect the passed component to be a Window so
we don't add it to the list of windows to be updated.

I don't know if this is an expected behavior from
getWindowAcnestor(), but it looks suspicious to me.

It works if the following fix is applied to RepaintManager.java:
*** RepaintManager.java: 1.72
--- RepaintManager.java
***************
*** 723,729 ****
          Set<Window> windows = new HashSet<Window>();

          for (Component dirty : dirtyComponents) {
!             Window window = SwingUtilities.getWindowAncestor(dirty);
              if (window != null) {
                  windows.add(window);
              }
--- 723,732 ----
          Set<Window> windows = new HashSet<Window>();

          for (Component dirty : dirtyComponents) {
!             Window window = dirty instanceof Window ?
!                 (Window)dirty :
!                 SwingUtilities.getWindowAncestor(dirty);
!
              if (window != null) {
                  windows.add(window);
              }

Another quirks I found:
   - you must set your component to be single-buffered
     by calling setDoubleBuffered(false).
     Since apparently this property doesn't propagate to children,
     it has to be done manually for all children of your
     non-opaque JFrames.
     It would be better if this was done automatically: when a jcomponent
     is added to a non-opaque frame, it should automatically be switched
     to be single-buffered. If the status of the frame changes to
     opaque, it should probably reset the property for all children.
   - in my JPanel.paintComponent() I had to do
     g.clearRect(0,0,w,h) first, or call super.paintComponent()
   - make sure to set your components' opaqueness to 'false'
     by calling setOpaque(false)
Posted Date : 2008-03-03 23:41:20.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang