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(childB order);
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(childScrollPa ne);
mainFrame.getContentPane() .add(mainP ane);
/*mainFrame.getContentPane ().add(chi ldScrollPa ne);*/
mainFrame.pack();
mainFrame.setVisible(true) ;
}
}
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(childB
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(childScrollPa
mainFrame.getContentPane()
/*mainFrame.getContentPane
mainFrame.pack();
mainFrame.setVisible(true)
}
}
ASKER
Edited text of question.
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.
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(n ew Dimension(500, 600));
jLabel1.setText("jLabel1") ;
jLabel2.setText("jLabel2") ;
jLabel3.setText("jLabel3") ;
jLabel4.setText("jLabel4") ;
jLabel5.setText("jLabel5") ;
jLabel6.setText("jLabel6") ;
this.getContentPane().add( jScrollPan e1, BorderLayout.CENTER);
jScrollPane1.getViewport() .add(jPane l1, 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
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(n
jLabel1.setText("jLabel1")
jLabel2.setText("jLabel2")
jLabel3.setText("jLabel3")
jLabel4.setText("jLabel4")
jLabel5.setText("jLabel5")
jLabel6.setText("jLabel6")
this.getContentPane().add(
jScrollPane1.getViewport()
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
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(
to
JPanel jPanel2 = new JPanel();
jPanel2.add(jScrollPane1, BorderLayout.CENTER);
this.getContentPane().add(
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
ASKER
Adjusted points to 150
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
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
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
"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
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
GridLayout resizes the contained component and arranges in a grid-like manner. That is why it works in the example.
Cheers,
Nik
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
Still a mystery as to exactly why Border and GridLayout work while FlowLayout doesn't.
Thanks,
Troy
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.
Add the jscrollpane to the mainframe, then add the component to scroll to the jscrollpane by:
scrollpane.setViewportView
Sometimes when the child panel changes size dynamically, you have to notify by calling the JScrollPane1.getViewPort()
Greetings,
Nikolay