Jesse
Jesse

Reputation: 273

JScrollPane can resize smaller, but JTextArea does not

I have a window containing a JScrollArea, which contains a JPanel which contains a JTextArea. When I resize the window to make it larger, the layout updates perfectly, but if I make the window smaller, the JPanel does not shrink its contents. I attempted to add a ComponentListener on the JScrollArea to resize the JPanel based on the new size of the viewport, but this seems to defeat the purpose of the vertical scroll bar.

UPDATE: The idea here is that the JScrollArea will contain a JPanel (since it can only contain one component for its viewport), and within that JPanel I will be adding multiple JPanels containing components that describe processes that are running to the user. Since there could be any number of these processes running, I need to have some kind of scroll bar functionality available. Hence the component hierarchy I'm using below.

The desired behavior here is that the window can be resized larger or smaller and the text area will wrap its contents accordingly, and a vertical scroll bar will appear if the contents of the JPanel are larger vertically than the window. Any suggestions?

public class TestWindow extends JFrame {
    JPanel scrollContentPanel;
    JScrollPane scrollPane;

    public TestWindow() {
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel mainPanel = new JPanel();
        this.setContentPane(mainPanel);
        GridBagLayout mainPanelLayout = new GridBagLayout();
        mainPanel.setLayout(mainPanelLayout);

        scrollContentPanel = new JPanel();
        scrollPane = new JScrollPane();
        scrollPane.setViewportView(scrollContentPanel);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        GridBagLayout scrollContentLayout = new GridBagLayout();
        scrollContentPanel.setLayout(scrollContentLayout);

        JPanel contentEntry = new JPanel();
        GridBagConstraints contentEntryConstraints = new GridBagConstraints();
        contentEntryConstraints.weightx = 1.0;
        contentEntryConstraints.insets = new Insets(3, 3, 5, 3);
        contentEntryConstraints.fill = GridBagConstraints.BOTH;
        contentEntryConstraints.gridx = 0;
        contentEntryConstraints.gridy = 1;
        scrollContentPanel.add(contentEntry, contentEntryConstraints);
        GridBagLayout contentEntryLayout = new GridBagLayout();
        contentEntry.setLayout(contentEntryLayout);

        JTextArea descTextArea = new JTextArea();
        descTextArea.setEditable(false);
        descTextArea.setFont(new Font("Dialog", Font.PLAIN, 11));
        descTextArea.setText("This is a description of an arbitrary unspecified length that may easily span multiple lines without any breaks in-between.  Therefore it is necessary that the description automatically wrap as appropriate.");
        descTextArea.setLineWrap(true);
        descTextArea.setWrapStyleWord(true);
        GridBagConstraints descTextAreaConstraints = new GridBagConstraints();
        descTextAreaConstraints.weightx = 1.0;
        descTextAreaConstraints.weighty = 1.0;
        descTextAreaConstraints.insets = new Insets(0, 0, 3, 0);
        descTextAreaConstraints.fill = GridBagConstraints.BOTH;
        descTextAreaConstraints.gridx = 0;
        descTextAreaConstraints.gridy = 1;
        descTextAreaConstraints.gridwidth = 2;
        contentEntry.add(descTextArea, descTextAreaConstraints);
        GridBagConstraints scrollPaneConstraints = new GridBagConstraints();
        scrollPaneConstraints.insets = new Insets(0, 0, 5, 0);
        scrollPaneConstraints.weightx = 1.0;
        scrollPaneConstraints.weighty = 1.0;
        scrollPaneConstraints.fill = GridBagConstraints.BOTH;
        scrollPaneConstraints.gridx = 0;
        scrollPaneConstraints.gridy = 0;
        mainPanel.add(scrollPane, scrollPaneConstraints);

        scrollPane.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent evt) {
                super.componentResized(evt);

                scrollContentPanel.setPreferredSize(scrollPane.getViewportBorderBounds().getSize());
                scrollContentPanel.validate();
            }
        });

        pack();
    }

    public static void main(String[] args) {
        TestWindow wnd = new TestWindow();
        wnd.setVisible(true);
    }
}

Upvotes: 1

Views: 1190

Answers (2)

matt forsythe
matt forsythe

Reputation: 3912

JTextArea should be placed directly into the JScrollPane, as long as that is the component your are trying to scroll. If there are other items you want to scroll with it (and hence the intermediate JPanel), then you might want to consider making that JPanel implement Scrollable so that the JScrollPane knows what to do with it. JTextArea implements Scrollable, which is why it works with JScrollPane out of the box.

Upvotes: 3

mKorbel
mKorbel

Reputation: 109815

  • no idea about your goal without detailed description, explanation

  • JTextArea should be placed in JScrollPane

  • set intial setPreferredSize for JTextArea, e.g. JTextArea(5, 10)

  • you are put three JPanels (is there reason ??? for this components hierarchy) one to JScrollPane, JTextArea is placed directly into JPanel instead of to the JScrollPane

  • then usage of ComponentListener is useless and contraproductive

Upvotes: 3

Related Questions