jScrollPane can't add component
Asked Answered
M

1

4

I have a jScrollPane and a button on a form. The button adds a component to the jScrollPane. I'm using a FlowLayout with a center alignment to arrange the components within the jScrollPane.

The first component has no problems appearing and is aligned perfectly. When I then hit the button again, nothing seems too happen. When I follow the debugger it shows that everything happens precisely as before.

The code that's being executed when the button is clicked:

jScrollPane.getViewport().add(new Component());

This is how I setup the FlowLayout on the Viewport of the jScrollPane:

jScrollPane.getViewport().setLayout(new FlowLayout(FlowLayout.CENTER));
Medical answered 4/1, 2013 at 0:51 Comment(1)
1) "The button adds a component to the jScrollPane." a) It is JScrollPane (note the capital J) b) Why do it on button click rather than when the GUI is created? What is the use-case to alter the existing GUI here? 2) On jScrollPane.getViewport().add(new Component()); Don't add AWT based components to Swing GUIs without good cause. For testing add a 'realistic' component - a default JTree comes with some data. 3) For better help sooner, post an SSCCE.Danicadanice
A
9

You're mixing heavy weight (AWT) components with light weight (Swing) components, this is inadvisable as they don't tend to play well together.

JScrollPane contains a JViewPort onto which you can add a child component, AKA the view.

enter image description here

(image from the JavaDocs)

So the call jScrollPane.getViewport().setLayout(new FlowLayout(FlowLayout.CENTER)); is actually setting the JViewPort's layout manager, which really isn't advisable.

What you should do is create the component you want to add to the scrollpane, set it's layout and add all it's child components to it and then add it to the scroll pane. You can add components to the "view" at later stage if you want, but that's up to you...

// Declare "view" as a class variable...
view = new JPanel(); // FlowLayout is the default layout manager
// Add the components you need now to the "view"
JScrollPane scrollPane = new JScrollPane(view);

Now you can add new components to the view as you need...

view.add(...);

If you don't want to maintain a reference to view, you can access it by calling JViewport#getView which will return the component been managed by the view port.

JPanel view = (JPanel)scrollPane.getViewPort().getView();

Working Example

This works fine for me...

nb - I added view.validate() to my code, which you may not have had, after I added a new component...

public class TestScrollPane01 {

    public static void main(String[] args) {
        new TestScrollPane01();
    }

    public TestScrollPane01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MainPane extends JPanel {

        private JScrollPane scrollPane;
        private int count;

        public MainPane() {
            setLayout(new BorderLayout());
            scrollPane = new JScrollPane(new JPanel());
            ((JPanel)scrollPane.getViewport().getView()).add(new JLabel("First"));
            add(scrollPane);

            JButton add = new JButton("Add");
            add.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JPanel view = ((JPanel)scrollPane.getViewport().getView());
                    view.add(new JLabel("Added " + (++count)));
                    view.validate();
                }
            });

            add(add, BorderLayout.SOUTH);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}
Ahead answered 4/1, 2013 at 2:54 Comment(3)
I set it up as you suggested. When I try to hit the button nothing happens. I instantiate the JScrollPane with a JPanel as a view and done the rest precisely like you suggested. Code on button event: ((JPanel)JScrollPane.getViewport().getView()).add(new JComponent()); Code on instantiation: JScrollPane = new javax.swing.JScrollPane(new JPanel(new FlowLayout(FlowLayout.CENTER)));Medical
Thank you very much! It indeed was the validate() that did the trick. Just one question, I saw that when the components on the view exceeded the view I couldn't scroll. Did I set up the JScrollPane wrongly?Medical
You could try revalidate instead of validateAhead

© 2022 - 2024 — McMap. All rights reserved.