United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6670649 Swing JFrames don't get repainted once shown if JFrame.repaint() is called
JDK-6670649 : Swing JFrames don't get repainted once shown if JFrame.repaint() is called

Details
Type:
Bug
Submit Date:
2008-03-03
Status:
Closed
Updated Date:
2011-03-15
Project Name:
JDK
Resolved Date:
2008-03-18
Component:
client-libs
OS:
windows_xp
Sub-Component:
java.awt
CPU:
x86
Priority:
P2
Resolution:
Fixed
Affected Versions:
6u10
Fixed Versions:
6u10 (b14)

Related Reports
Backport:

Sub Tasks

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.

                                    

Comments
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)
                                     
2008-03-03
SUGGESTED FIX

*** 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);
              }
                                     
2008-03-03
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.
                                     
2008-03-03
SUGGESTED FIX

http://sa.sfbay.sun.com/projects/java2d_data/6u10/6670649.0
                                     
2008-03-05



Hardware and Software, Engineered to Work Together