1

Working with the JTreeWithScrollbar example, but scaled it back significantly to focus on the issue.

The original code would have the vertical scrollbars appear as needed.

Here, there is plenty of space and no scrollbars are needed.

enter image description here

If the panel is moved enough, the scrollbar will appear.

enter image description here

Once the following line of code was added, the scrollbars stopped appearing.

        tree.setUI(new MyTreeUI());

Notice no scrollbar.

enter image description here

If the above line of code is commented out, the vertical scrollbar appears.

Checking the documentation for BasicTreeUI and there isn't anything related to showing/hiding scrollbars.

2 Questions

1 - When utilizing the BasicTreeUI object, what is required to ensure the scrollbars still function?

2 - Why is it the Horizontal scrollbar never appears even if the line of code is commented out?

import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.Dimension;

public class JTreeWithScrollbar extends JPanel { 
    private JEditorPane htmlPane;
    private JTree tree;

    public JTreeWithScrollbar() 
    {
        //Create the nodes. 
        DefaultMutableTreeNode top =  new DefaultMutableTreeNode("The Java Series");
        DefaultMutableTreeNode book1Node = new DefaultMutableTreeNode("Book 1");
        DefaultMutableTreeNode book2Node = new DefaultMutableTreeNode("Book 2");
        top.add(book1Node);
        top.add(book2Node);     

        tree = new JTree(top);
        tree.setUI(new MyTreeUI());  ///Comment out this line of code and the vertical scrollbar appears.

        JScrollPane treeView = new JScrollPane(tree);

        JScrollPane htmlView = new JScrollPane(htmlPane);

        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        splitPane.setTopComponent(treeView);
        splitPane.setBottomComponent(htmlView);

        Dimension minimumSize = new Dimension(100, 50);
        htmlView.setMinimumSize(minimumSize);
        splitPane.setDividerLocation(100); 
        splitPane.setPreferredSize(new Dimension(500, 300));
        add(splitPane);
    }
    
    public static void main(String[] args) 
    {
        //Create and set up the window.
        JFrame frame = new JFrame("TreeDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel jp = new JPanel();
        jp.add(new JTreeWithScrollbar());
        frame.add(jp);


        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }
    
    
    private static class MyTreeUI extends BasicTreeUI 
    {
        public MyTreeUI() 
        {
            super();
        }

        @Override
        protected void updateCachedPreferredSize() {
            treeState.invalidateSizes();
            tree.treeDidChange();
        }
        
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Unhandled Exception
  • 1,427
  • 14
  • 30
  • I have very limited knowledge in this subfield of Swing GUI, but in the BasicTreeUI, both the `protected void toggleExpandState​(TreePath path)` and the `protected void ensureRowsAreVisible​(int beginRow, int endRow)` methods are mentioned with regards to scrolling. The former API entry states: *"Expands path if it is not expanded, or collapses row if it is expanded. If expanding a path and JTree scrolls on expand, ensureRowsAreVisible is invoked to scroll as many of the children to visible as possible (tries to scroll to last visible descendant of path)."* – Hovercraft Full Of Eels Jul 05 '22 at 22:14
  • 2
    Why do you need to override `updateCachedPreferredSize()`? – trashgod Jul 05 '22 at 23:04

1 Answers1

2
  1. When utilizing the BasicTreeUI object, what is required to ensure the scrollbars still function?

As shown in the minimal example below, BasicTreeUI correctly shows each scroll bar when needed; resize the frame to see the effect.

  1. Why does the horizontal scrollbar never appear even if the line of code is commented out?

After pack() the frame has been resized to adopt the preferred size of it content. Making the frame slightly smaller illustrates the effect. Your example adds the tree to a JPanel having a default FlowLayout which ignores preferred sizes; the example below adds the tree to the center of the frame's default BorderLayout which responds to preferred sizes.

  1. I am assuming the updateCachedPreferredSize() must be doing other stuff behind the scenes…

Exactly. Each invocation of updateCachedPreferredSize() updates the component's preferred size to reflect any change in state (resize, expand, etc.); when the preferred size exceeds the viewport size, the scroll bars appear. As you observed, invoking super.updateCachedPreferredSize() allows normal operation, and any further customization must preserve that functionality.

In addition,

  • Expand rows as need like this.

  • Construct and manipulate Swing GUI objects only on the event dispatch thread.

  • Don't use setSize() when you really mean to override getPreferredSize() or illustrates a resize effect; more here.

Tree

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.plaf.basic.BasicTreeUI;

public class JTreeWithScrollbar {

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            //Create and set up the window.
            JFrame frame = new JFrame("TreeDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JTree tree = new JTree(); //default model
            for (int i = 0; i < tree.getRowCount(); i++) {
                tree.expandRow(i);
            }
            tree.setUI(new MyTreeUI());
            frame.add(new JScrollPane(tree));

            //Display the window.
            frame.pack();
            frame.setSize(frame.getWidth() - 10, frame.getHeight() - 100);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }

    private static class MyTreeUI extends BasicTreeUI {
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks, but as with the original example, your sample fails if the updateCachedPreferredSize() is overridden in the MyTreeUI class. – Unhandled Exception Jul 06 '22 at 11:55
  • I am assuming the updateCachedPreferredSize() must be doing other stuff behind the scenes so as a test, I added "super.updateCachedPreferredSize();" as the first line and now the scrollbars appear. – Unhandled Exception Jul 06 '22 at 12:02
  • 1
    _I am assuming the updateCachedPreferredSize() must be doing other stuff behind the scenes_ - no need to assume, look at the sources if the doc is so sparse as in this case (with the usual caveat that unspecified behavior might break in different LaFs or in future) – kleopatra Jul 06 '22 at 15:53
  • I did search was unable to locate the source for updateCachedPreferredSize(). – Unhandled Exception Jul 06 '22 at 17:47
  • I cited a familiar version above, but your IDE may be able to show yours. – trashgod Jul 06 '22 at 17:54
  • _I did search was unable to locate the source_ it's where all sources of the jdk are, in src.zip, you IDE should show them automatically (f.i. when opening super). Without looking into the sources, successfully extending the uis is near to impossible, IMO. – kleopatra Jul 07 '22 at 09:15
  • 1
    @kleopatra is correct on both counts: read the sources, but critically examine whether this is the best way to solve your [underlying problem](http://meta.stackoverflow.com/q/66377/163188). – trashgod Jul 07 '22 at 12:05