Search code examples
javaswingscrolljtextareajtabbedpane

Java Swing: Nested Tabs and Layouts


I'm having an issue with next JTabbedPanes that has me stumped. I've isolated the issue into a short demo application (based on the oracle tabbed pane tutorial):

package main.java;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class TabbedPaneDemo extends JPanel {

public static JTabbedPane topTabs = new JTabbedPane();

public TabbedPaneDemo() {
    super(new BorderLayout());

    topTabs.setPreferredSize(new Dimension(400, 200));

    topTabs.add(makeReadoutPanel("\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15"));

    add(topTabs);
}

private static JTabbedPane makeReadoutPanel(String text) {
  // Create tabbed pane
  JTabbedPane tabs = new JTabbedPane();
  tabs.setName("Tabs");

  // Create text field
  JTextArea textArea = new JTextArea(text);
  textArea.setEditable(false);
  textArea.setFont(new Font("Monospaced", Font.PLAIN, 14));

  // Create first panel for text field
  JPanel textPanel = new JPanel();
  textPanel.setLayout(new BorderLayout());
  textPanel.setName("Text Panel");
  textPanel.add(textArea, BorderLayout.CENTER);

  // Add text field panel to tabs
  tabs.add(textPanel);

  return tabs;
}

private static void createAndShowGUI() {
    //Create and set up the window.
    JFrame frame = new JFrame("TabbedPaneDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Add content to the window.
    frame.add(new TabbedPaneDemo(), BorderLayout.CENTER);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
}

public static void main(String[] args) {
    //Schedule a job for the event dispatch thread:
    //creating and showing this application's GUI.
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          //Turn off metal's use of bold fonts
          UIManager.put("swing.boldMetal", Boolean.FALSE);
          createAndShowGUI();
        }
    });
}
}

When this is run, the JTextArea gets cut off, without a scroll bar, rather than fitting vertically to the panel. Shouldn't the BorderLayout in the textPanel make the text area size to the tabs? This only happens with nested tabs: if I use only a single level of tabs the text area fits properly.


Solution

  • You need to add the JTextArea to the viewport of a JScrollBar and then add that to the component held by the JTabbedPane.

    JPanel textPanel = new JPanel();
    textPanel.setLayout(new BorderLayout());
    textPanel.setName("Text Panel");
    
    // **** note change:
    textPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
    

    Note that there are two common ways to add the component (JTextArea here) the viewport. One is to pass it into the JSrollPane's constructor as noted above, and another is to call setViewportView(...) on an already created JScrollPane passing in the component into the method's parameter. Whatever you do, do not pass the JTextArea into an already created JScrollPane with its add(...) method as you'll remove the scrollpane's veiwport, and this will prevent it from working properly.