JDK-4180658 : JTree.scrollPathToVisible not scrolling
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.1.7,1.2.0,1.2.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,windows_95,windows_nt
  • CPU: unknown,x86
  • Submitted: 1998-10-12
  • Updated: 1998-12-02
  • Resolved: 1998-12-01
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 Availability Release.

To download the current JDK release, click here.
Other
1.2.2 1.2.2Fixed
Related Reports
Duplicate :  
Duplicate :  
Description

Name: tb29552			Date: 10/12/98


/*

JTree.scrollPathToVisible doesn't work properly
under certain circumstances. The makeVisible
portion of the logic is fine and always expands
the path, but the ScrollPathTo part can fail.
I find that it works when the 1st node of the
path that needs to expand is already in the
viewport. It fails when this 1st node is not in
the view port. It does manage to scroll to this
first node, but not down to the final node in the
path.

Problem exists on Swing 1.1beta3 and for both
the Windows and Java look & feel.

The code to reproduce is listed at the end.

The steps to reproduce are:
1. Run JTreeBugA application
2. Expand first folder, "Livingroom"
3. Press button and confirm that JTree does not
scroll down sufficiently to the "Toys" node,
but only to the Bedroom folder in the TreePath
of the "Toys" node.

To confirm situation that does work:
1. Run JTreeBugA application
2. Press button and confirm complete ScrollTo
behavior making it to the "Toys" node.

*/

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

public class JTreeBugA extends JApplet {

    static int WIDTH = 300;
    static int HEIGHT = 200;

    public static void main(String args[]) {
        JFrame jframe = new JFrame();
        JTreeBugA JTreeBugA = new JTreeBugA ();
        jframe.getContentPane().add(JTreeBugA, BorderLayout.CENTER);
        JTreeBugA.init();
        jframe.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        jframe.setSize(WIDTH, HEIGHT);
        jframe.setVisible(true);
    }

    public void init() {

        try {
            // Don't switch to WindowsL&F if somehow already
            // WindowsL&F. I see this as a potential savings for
            // Applets.
            if (!UIManager.getLookAndFeel().getID().equals("Windows")) {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            }
        }
        catch(Exception e) {
            System.err.println("Can't change look&feel! " + e);
        }

        getContentPane().setLayout(new GridLayout(1, 1));
        setSize(WIDTH - 10, HEIGHT - 10);

        // The house.
        DefaultMutableTreeNode house = new DefaultMutableTreeNode("My House");
        // Rooms.
        DefaultMutableTreeNode livingroom = new DefaultMutableTreeNode("Livingroom");
        DefaultMutableTreeNode kitchen = new DefaultMutableTreeNode("Kitchen");
        DefaultMutableTreeNode foyer = new DefaultMutableTreeNode("Foyer");
        DefaultMutableTreeNode dinningroom = new DefaultMutableTreeNode("Dinningroom");
        DefaultMutableTreeNode bedroom = new DefaultMutableTreeNode("Bedroom");
        // My stuff.
        DefaultMutableTreeNode picture = new DefaultMutableTreeNode("Picture");
        DefaultMutableTreeNode lazyboy = new DefaultMutableTreeNode("LazyBoy");
        DefaultMutableTreeNode tv = new DefaultMutableTreeNode("TV");
        DefaultMutableTreeNode sofa = new DefaultMutableTreeNode("Sofa");
        DefaultMutableTreeNode table = new DefaultMutableTreeNode("Table");
        DefaultMutableTreeNode chair[] = new DefaultMutableTreeNode[6];
        chair[0] = new DefaultMutableTreeNode("Chair");
        chair[1] = new DefaultMutableTreeNode("Chair");
        chair[2] = new DefaultMutableTreeNode("Chair");
        chair[3] = new DefaultMutableTreeNode("Chair");
        chair[4] = new DefaultMutableTreeNode("Chair");
        chair[5] = new DefaultMutableTreeNode("Chair");
        DefaultMutableTreeNode pots = new DefaultMutableTreeNode("Pots");
        DefaultMutableTreeNode stove = new DefaultMutableTreeNode("Stove");
        DefaultMutableTreeNode silver = new DefaultMutableTreeNode("Silver");
        DefaultMutableTreeNode bed = new DefaultMutableTreeNode("Bed");
        DefaultMutableTreeNode toyChest = new DefaultMutableTreeNode("Toy Chest");
        final DefaultMutableTreeNode toys = new DefaultMutableTreeNode("Toys");

        // Build the house
        house.add(livingroom);
        house.add(kitchen);
        house.add(foyer);
        house.add(dinningroom);
        house.add(bedroom);
        // Fill the livingroom
        livingroom.add(sofa);
        livingroom.add(tv);
        livingroom.add(picture);
        livingroom.add(lazyboy);
        // Fill the kitchen
        kitchen.add(pots);
        kitchen.add(silver);
        kitchen.add(stove);
        // The diningroom
        dinningroom.add(table);
        for (int i = 0; i < chair.length; i++) {
            table.add(chair[i]);
        }

        // The bedroom
        bedroom.add(bed);
        bedroom.add(toyChest);
        toyChest.add(toys);

        final JTree tree = new JTree(house);

        // Create a scrollpane with the tree so that we can
        // add to the tree and not worry about its size.
        JScrollPane scrollpane = new JScrollPane(tree);
        Container content = getContentPane();
        content.setLayout(new BorderLayout());
        content.add(scrollpane, BorderLayout.CENTER);
        JPanel jPanel = new JPanel();
        jPanel.setLayout(new FlowLayout());

        JButton finderButton = new JButton("find last node, 'toys'");
        ActionListener findNodeListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                TreePath path = new TreePath(toys.getPath());
                // SwingBug: scrollTo fails when ancestor node not
                // already in viewport
                tree.scrollPathToVisible(path);
                // Double method invoke works around bug where
                // viewport only gets to ancestor.
                /* tree.scrollPathToVisible(path); */
            }
        };
        finderButton.addActionListener(findNodeListener);

        jPanel.add(finderButton);
        content.add(jPanel, BorderLayout.NORTH);
    }                           // end init()
}

(Review ID: 40295)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic FIXED IN: 1.2.2 swing2.0alpha INTEGRATED IN: 1.2.2
14-06-2004

EVALUATION When a node is expanded/collapsed the bounds do not change immediately. Rather JTree uses revalidate to schedule a validate to happen. For this reason scrollRectToVisible will fail the first time. The reason it works the second time is buried deep in BasicScrollPaneUI, and I will not get into it. The real fix is to make the methods that require the component be validated check if the component is valid, and if it is not valid call validateInvalidComponent on the RepaintManager to make it valid. sky 1998-10-20 JViewport has been changed so that in scrollRectToVisible it will validate the validateRoot if its component is invalid. This fixs the bug, and others like it, assuming the component is contained in a JViewport. scott.violet 1998-10-29
11-06-2004

WORK AROUND Name: tb29552 Date: 10/12/98 Invoke the scrollPathToVisible method twice. ======================================================================
11-06-2004

PUBLIC COMMENTS JViewport has been changed so that in scrollRectToVisible it will validate the validateRoot if its component is invalid. This fixs the bug, and others like it, assuming the component is contained in a JViewport. scott.violet 1998-10-29
10-06-2004