JDK-4304100 : Swing components don't repaint properly
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version:
    1.2.1,1.2.1_04,1.2.2,1.3.0,1.3.0_02,1.4.0 1.2.1,1.2.1_04,1.2.2,1.3.0,1.3.0_02,1.4.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,solaris_2.6,windows_nt
  • CPU: generic,x86,sparc
  • Submitted: 2000-01-12
  • Updated: 2000-03-22
  • Resolved: 2000-03-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
Other
1.4.0 betaFixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description

Name: krT82822			Date: 01/11/2000


12/19/99  -- NOT reproducible with 1.2 FCS, 1.2.1 or 1.2.2 reference (green threads versions) under Solaris 2.7, so must be Solaris (native threads) specific?
-------------
java version "1.2.1"
Solaris VM (build Solaris_JDK_1.2.1_04, native threads, sunwjit)

I have a test case where a component acts like a tree branch, listening for
mouse clicks and alternating between an open and closed state.  An open state
displays components underneath.

However, when the branch is opened the tree doesn't appear until the window is
resized.  Once the window is resized, you can open and close the tree to your
heart's content, until you resize while the tree is closed.  Then you're back
to the original behavior.

Here's the code I'm working with:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class RepaintBug extends JFrame {
   public static void main(String args[]){
      new RepaintBug().show();
   }

   public RepaintBug(){
      setSize(640, 480);
      Container cp = getContentPane();
      cp.setLayout(new BorderLayout());
      FlowTreeNode ftn = new FlowTreeNode();
      ftn.addChild(new Label("Child 1"));
      ftn.addChild(new Label("Child 2"));
      ftn.addChild(new Label("Child 3"));
      ftn.addChild(new Label("Child 4"));
      ftn.addChild(new Label("Child 5"));
      cp.add(ftn, BorderLayout.CENTER);
   }
}


class FlowTreeNode extends JPanel {
   boolean isOpen = false;
   ImageIcon open = new ImageIcon(getClass().getResource("opennode.gif"));
   ImageIcon closed = new ImageIcon(getClass().getResource("closednode.gif"));
   Box expandedNode;
   JLabel button;
   public FlowTreeNode(){
      super(new BorderLayout());
      button = new JLabel(closed);
      add(button, BorderLayout.CENTER);
      expandedNode = Box.createVerticalBox();
      expandedNode.setVisible(false);
      add(expandedNode, BorderLayout.SOUTH);
      button.addMouseListener(new MouseAdapter(){
         public void mouseClicked(MouseEvent e){
            if(!e.isPopupTrigger()){
               if(isOpen){
                  button.setIcon(closed);
                  expandedNode.setVisible(false);
                  isOpen = false;
               }
               else{
                  button.setIcon(open);
                  expandedNode.setVisible(true);
                  isOpen = true;
               }
            }
         }
      });
   }

   public Component addChild(Component comp){
      return expandedNode.add(comp);
   }
}
(Review ID: 99108) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic FIXED IN: merlin-beta INTEGRATED IN: merlin-beta
2004-06-14

EVALUATION This behavior (which I'm not yet sure is a bug) is due to the fact that the swing Box class does not extend JComponent but instead directly extends Container. When a normal Swing component (that extends JComponent) is setVisible, it is marked as invalid and is added to the RepaintManager invalid component list. When a paint occurs, the component is validated which causes the layout manager to layout the component, and it gets sized and painted. With the Box class (or any component that doesn't extend JComponent), when the Box is setVisible, the Box is never added to the Swing invalid component list because it doesn't extend JComponent, and the layout manager is never called to layout the Box. The Box and its subcomponents never get painted. In AWT, it was up to the programmer to call validate() when a subcomponent of an already-showing Window was added or setVisible. It needs to be investigated whether this is actually a bug; should Box, being in the Swing package, behave like Swing components that extend JComponent? Or should it act like AWT components since it does not extend JComponent and cannot be (easily) made compatible with the Swing RepaintManager? -stephen.bohne@East 2000-01-18 I was able to reproduce this with JavaSoft reference 1.2.2 and 1.3beta, this should be a more general java category bug (not java_solaris). -stephen.bohne@East 2000-01-19 A long time ago we had a discussion on whether or not Box needed to be a JComponent and decided not to change it since one could easily add BoxLayout to a JComponent and have the desired functionality. This report shows a motiviation to change Box however, as one gets lured into a repaint problem using Box in Swing, when box is a part of Swing. Box will be upgraded to be a JComponent. timothy.prinzing@eng 2000-03-10
2000-03-10

WORK AROUND Name: krT82822 Date: 01/11/2000 None known... tried lots of stuff including invalidating components and attempting to force repaints. ====================================================================== after the line expandedNode.setVisible(true) in the Listener, add the following line: validate(); That will cause the FlowTreeNode to be validated after the setVisible, which results in it asking the current layout manager to layout the components inside it, thus repainting the expandedNode component. -stephen.bohne@East 2000-01-18
2000-01-18