JScrollPane Vertical only
Hi!
I have a JScrollPane with a JPanel inside , and the JPanel is using a Flow Layout aligned left and with gap 2*2, in a Bean.
I have a Code that will add buttons inside the JPanel, and i am using Flow Layout so the buttons will be positioned good
The problem is that the JScrollPane allow JPanel to be resized Vertical and Horizontal so the buttons get all in one line.
How can i make a vertical only JScrollPane? I tried to mess around the JViewPort but i am not having success
[512 byte] By [
porfirioa] at [2007-10-3 8:20:53]

Create a subclass of JPanel which implements the Scrollable interface, have it return true for the method getTrackViewportWidth(). Then add such a JPanel to the ScrollPane.
> Create a subclass of JPanel which implements the Scrollable
> interface, have it return true for the method getTrackViewportWidth(). Then add such a JPanel to the ScrollPane
The OP wants the buttons to wrap automatically to a second line when a button execeeds the width of the scrollpane. At least thats how I interpret the question.
I don't understand how your suggestions does this. This is the code I tried. It's worse than not using the Scrollable interface, because now the horizontal scrollbar doesn't even show up.
import java.awt.*;
import javax.swing.*;
public class ScrollablePanel extends JPanel implements Scrollable
//public class ScrollablePanel extends JPanel
{
public Dimension getPreferredScrollableViewportSize()
{
return getPreferredSize();
}
public int getScrollableUnitIncrement(
Rectangle visibleRect, int orientation, int direction)
{
return 20;
}
public int getScrollableBlockIncrement(
Rectangle visibleRect, int orientation, int direction)
{
return 60;
}
public boolean getScrollableTracksViewportWidth()
{
return true;
}
public boolean getScrollableTracksViewportHeight()
{
return false;
}
public static void main(String[] args)
{
JPanel panel = new ScrollablePanel();
for (int i = 0; i < 20; i++)
panel.add( new JButton("Button" + i) );
JScrollPane scrollPane = new JScrollPane( panel );
scrollPane.setPreferredSize( new Dimension(300, 100) );
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add( scrollPane );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
Maybe you have an actual implementation that works that you can share.
The problem is actually with the interaction between the Panel with a flow layout and the layout manager of the scrollpane. Specifically, the flow layout returns a minimum and preferred height as if it were going to layout all of its components on a single row. So, unless that panel is put into a container which will size it bigger than it's preferred size (like the CENTER spot of a BorderLayout), the Panel only gets 1 row worth of height, and thus only the 1st row of components is actually visible. I modified your example to use a FlowLayout which is more friendly with being in a JSrollPane.
import java.awt.*;
import javax.swing.*;
public class ScrollablePanel extends JPanel implements Scrollable
//public class ScrollablePanel extends JPanel
{
public Dimension getPreferredScrollableViewportSize()
{
return getPreferredSize();
}
public int getScrollableUnitIncrement(
Rectangle visibleRect, int orientation, int direction)
{
return 20;
}
public int getScrollableBlockIncrement(
Rectangle visibleRect, int orientation, int direction)
{
return 60;
}
public boolean getScrollableTracksViewportWidth()
{
return true;
}
public boolean getScrollableTracksViewportHeight()
{
return false;
}
public static void main(String[] args)
{
JPanel panel = new ScrollablePanel();
panel.setLayout(new BetterFlowLayout());
for (int i = 0; i < 20; i++)
panel.add( new JButton("Button" + i) );
JScrollPane scrollPane = new JScrollPane( panel );
scrollPane.setPreferredSize( new Dimension(300, 100) );
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add( scrollPane );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
/**
* This LayoutManager alters java.awt.FlowLayout to solve a problem with FlowLayout
* when FlowLayout needs to wrap the components. Specifically, the preferred height
* of a FlowLayout is always the height of 1 row of components, not the total height
* of all the rows, which sometimes results in only the first row of components being
* visible.
*/
static class BetterFlowLayout extends FlowLayout {
public BetterFlowLayout() {
super();
}
public BetterFlowLayout(int align) {
super(align);
}
public BetterFlowLayout(int align, int hgap, int vgap) {
super(align, hgap, vgap);
}
@Override
public Dimension preferredLayoutSize(Container target) {
return betterPreferredSize(target);
}
@Override
public Dimension minimumLayoutSize(Container target) {
return betterPreferredSize(target);
}
public Dimension betterPreferredSize(Container target) {
synchronized (target.getTreeLock()) {
Insets insets = target.getInsets();
int maxwidth = target.getWidth() - (insets.left + insets.right + getHgap()*2);
int nmembers = target.getComponentCount();
int x = 0, y = insets.top + getVgap();
int rowh = 0;
for (int i = 0 ; i < nmembers ; i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = m.getPreferredSize();
m.setSize(d.width, d.height);
if ((x == 0) || ((x + d.width) <= maxwidth)) {
if (x > 0) {
x += getHgap();
}
x += d.width;
rowh = Math.max(rowh, d.height);
} else {
x = d.width;
y += getVgap() + rowh;
rowh = d.height;
}
}
}
return new Dimension(maxwidth, y+rowh+getVgap());
}
}
}
}
> The problem is actually with the interaction between the Panel with a flow layout and the layout manager of the scrollpane.
Yes, I knew that, which is why I was surprised by your answer. I thought you knew of an easier way of wrapping a FlowLayout, without writing your own Layout Manager.
I have written my own which I called WrapLayout. Its code can be found here:
http://www.discoverteenergy.com/files/WrapLayout.java
I have noticed one significant difference between yours and mine. I've spent the last hour trying to figure out why its different but am coming up empty. If you have time maybe you can spot the difference.
First, when you download my class, just remove (or comment out) the layoutContainer(...) method from my class.
Second, I made your LayoutManager a separate class.
I added the following line of code to the top of my "layoutSize" method and your "betterPreferredSize" method:
System.out.println( target.getWidth() );
I then used the following main method to test both classes:
public static void main(String[] args)
{
JPanel panel = new JPanel();
//panel.setLayout(new BetterFlowLayout());
panel.setLayout(new WrapLayout());
for (int i = 0; i < 20; i++)
panel.add( new JButton("Button" + i) );
JScrollPane scrollPane = new JScrollPane( panel );
scrollPane.setPreferredSize( new Dimension(300, 100) );
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add( scrollPane );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
When I test your layout manager I get the following output:
0
0
0
282
282
When I test my layout manager I get the following output:
0
0
0
1735
I can't figure out why:
a) the width of the parent container would be different.
b) the number of lines of output would be different
Your layout managers wraps as expected, but obviously my layout manager does not wrap.
Any comments would be appreciated.
Don't you hate it when you make a post and then 5 minutes later realize what the problem (difference ) is.
The difference is that my routine overrides the width when it is equal to zero to allow all the components to be displayed on a single line, if in fact the container is that wide.
Because of this difference I also had to override the layoutContainer() method to get it to work correctly.
I guess my original answer is essentially worthless. Even though it does force the components to be wrapped by FlowLayout, the wrapped components are not visible. I can't think of any way to get FlowLayout wrapping to work correctly in this context. In fact, there are so few cases I can think of where the wrapping will work correctly I'm coming around to thinking it's a flaw.
Someone submitted it as a bug here http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5082531
Ah, so it was not just a problem mine , its a BUG!I'll checkout your code guys, Thank you!!Thank you mpmarrone, your code do exactly what i want, even better than i expected, i hope the bug get fixed for Java6Message was edited by: porfirio