Link to home
Start Free TrialLog in
Avatar of troys
troys

asked on

JScrollPane not scrolling

I am having troubles getting a JScrollPane to correctly scroll when needed.  I have a mainPanel that contains a childPanel.  The childPanel was added to a JScrollPane and then added to the mainPanel, however the childPanel never scrolls, even when needed.  Although when I add the scrollable childPanel directly to the main frame everything works.  Why does putting a scrollable panel into another panel cause things to break?

Here is the code:import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;

public class ScrollPane{

    public static void main(String[] Args)
    {
              JFrame mainFrame = new JFrame();

              final JPanel mainPane = new JPanel();
              final JPanel childPane = new JPanel(){
                               public Dimension getPreferredSize(){ Dimension size = new Dimension(350,100);
                               return size;
                               }

                               public Dimension getMaximumSize(){ Dimension size = new Dimension(350,100);
                               return size;
                               }
                        };
              TitledBorder childBorder = new TitledBorder("ChildPane");
              childPane.setBorder(childBorder);
              childPane.add( new Label("One") );
              childPane.add( new Label("Two") );
              childPane.add( new Label("Three") );
              childPane.add( new Label("Four") );
              childPane.add( new Label("Five") );

              JScrollPane childScrollPane = new JScrollPane( childPane );

              mainPane.add(childScrollPane);
              mainFrame.getContentPane().add(mainPane);
              /*mainFrame.getContentPane().add(childScrollPane);*/


              mainFrame.pack();
              mainFrame.setVisible(true);
       }
}


Avatar of diakov
diakov

The scheme works like this:

Add the jscrollpane to the mainframe, then add the component to scroll to the jscrollpane by:

 scrollpane.setViewportView(myBigComponentToScroll);

Sometimes when the child panel changes size dynamically, you have to notify by calling the JScrollPane1.getViewPort().revalidate()

Greetings,
  Nikolay
Avatar of troys

ASKER

Edited text of question.
Avatar of troys

ASKER

Hello Nikolay,

Thanks for the help, but I need the childPane to be scrollable and the mainPane to remain non-scrollable.  

I have a larger application that the above code fits into where making the mainPane scrollable will not work.

I tried playing around with the ViewPort.revalidate() but the childPane still didn't scroll.
I suggest another design:

ScrollPane.java
---------------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;

public class ScrollPane{

  public static void main(String[] Args)
  {
    TestFrame f = new TestFrame();
    f.setSize(300, 200);
    f.pack();
    f.setVisible(true);
  }
}

TestFrame.java
--------------
import java.awt.*;
import javax.swing.*;

public class TestFrame extends JFrame
{
  JScrollPane jScrollPane1 = new JScrollPane();
  JPanel jPanel1 = new JPanel();
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel5 = new JLabel();
  JLabel jLabel6 = new JLabel();

  public TestFrame()
  {
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception
  {
    jPanel1.setPreferredSize(new Dimension(500, 600));
    jLabel1.setText("jLabel1");
    jLabel2.setText("jLabel2");
    jLabel3.setText("jLabel3");
    jLabel4.setText("jLabel4");
    jLabel5.setText("jLabel5");
    jLabel6.setText("jLabel6");
    this.getContentPane().add(jScrollPane1, BorderLayout.CENTER);
    jScrollPane1.getViewport().add(jPanel1, null);
    jPanel1.add(jLabel1, null);
    jPanel1.add(jLabel2, null);
    jPanel1.add(jLabel3, null);
    jPanel1.add(jLabel4, null);
    jPanel1.add(jLabel5, null);
    jPanel1.add(jLabel6, null);
  }
}

This is scrolling now.

Cheers,
  Nik
Avatar of troys

ASKER


The problem is that the application that I am working on has a JPanel that contains 2 other JPanels, one that must scroll and one that must not scroll.  Your code above does work, however when you put the jScrollPane1 variable when added to another JPanel, it does not scroll.  This is the problem that I need to solve.

For example I changed the following line, this.getContentPane().add(jScrollPane1, BorderLayout.CENTER);  

to
            JPanel jPanel2 = new JPanel();
            jPanel2.add(jScrollPane1, BorderLayout.CENTER);
            this.getContentPane().add(jPanel2, BorderLayout.CENTER );

Once I do this the scrolling stops.  I agree that without putting a Scrolling Panel into a non scrolling Panel things work.  However this is what I would really like to figure out.

I have found that by using a BoxLayout or a BorderLayout the problem is solved. However the FlowLayout doesn't work. Does anyone know why?

Thanks
Avatar of troys

ASKER

Adjusted points to 150
ASKER CERTIFIED SOLUTION
Avatar of diakov
diakov

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of troys

ASKER


Thanks for you help.

When you say that the FlowLayout does not enforce resize of the contained component, where did you find this information out.  I looked at the Java API doc page and both FlowLayout and GridLayout both implement the LayoutManager.  I checked the class document for FlowLayout manager and didn't notice anything that would leave me to believe that it wouldn't work correctly in a JScrollPane.  I also looked at JScrollPane and JViewport and didn't find anything that would suggest that FlowLayout wouldn't work.

However, I agree that if you change the layout things beging to work.  I was able to get things to work with BorderLayout as well.  I think that from your original code, the only problem was that setLayout was never called, so the Panels were still using the default LayoutManager, which I think is Flow.

Thanks again for all of your help.  You've answered my original question but if you know exactly why FlowLayout manager doesn't work then I'll double the points.

Thanks
Troy

http://java.sun.com/docs/books/tutorial/uiswing/layout/flow.html

says :

"FlowLayout puts components in a row, sized at their preferred size. If the horizontal space in the container is too small to put all the components in one row, FlowLayout uses multiple rows. Within each row, components are centered (the default), left-aligned, or right-aligned as specified when the FlowLayout is created. "

Which essentially means that if the FlowLayout won't resize the component if its container size changes. In respect to the example this means that the FlowLayout will use the preferred size of the JScrollPane which in his turn gets it's preferred size from its view port (if no preferred size is set explicitly). The afore mentioned FlowLayout would also resize the container panel (if no preferred size has been set) to host all its components (jscrollpane) in its visible area.

After reading this again, for me the question is solved. Hope this helps.

Cheers,
  Nik
An addition to the sentence:
"The afore mentioned FlowLayout would also resize the container panel (if no preferred size has been set) to host all its components (jscrollpane) in its visible area."

This is the initial behaviour.

Nik
Avatar of troys

ASKER


I'm still a bit confused on why the FlowLayout won't work.  I don't understand why FlowLayout doesn't resize.  In the initial example all of the labels are put on one row.  When the space was reduced another row was not added, instead only one row was created and information would just be out of the visible region.

Also, I thought that I tried to catch the resize event and then reset the size of the Panel, that had a FlowLayout.  I also then did a call to invalidate, validate and repaint.  From the link that you listed, it seems like this should work.

I guess the question is, when you have a FlowLayout Panel and you add  components that together are larger than the Panel what does the FlowLayout do?  And what does a BoxLayout or GridLayout do that causes things to work?
I think, this is because the FlowLayout is set to the outside container A, and not the the container B that directly contains the labels. Container B never gets resized and its initial size (if not set) is enough to host the labels. Try setting preferred size for the B container.
GridLayout resizes the contained component and arranges in a grid-like manner. That is why it works in the example.

Cheers,
  Nik
Avatar of troys

ASKER

I'm still confused on why FlowLayout doesn't yet other lay managers do.  I caught the resize events and it seems like the inner container is never resized.  I checked this with both  a flowLayout and a BorderLayout of the mainPanel.  But the BorderLayout still did the scroll bars accordingly.

Still a mystery as to exactly why Border and GridLayout work while FlowLayout doesn't.

Thanks,
Troy
Avatar of troys

ASKER


This code works and helps with the original problem  of the scroll bars not showing up. I don't think that we ever really found out why FlowLayout doesn't work and other Layout managers do.