Skip to main content

JList resize pb

5 replies [Last post]
hsantos
Offline
Joined: 2005-04-07
Points: 0

Hi
I have a JList in a panel and want it to have always half the width of the panel. I use a GridBagLayout. Initially the list is empty and its width is what I expect. But once the list is populated, it resizes to the width of the largest displayed item.
I can avoid this with setPrototypeCellValue() or setFixedCellWidth(), but then the list never resizes when the panel's width changes.
I tried other layout managers, but couldn't find a working one.
What can I do to force my list to always have half the width of the enclosing panel ?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
hsantos
Offline
Joined: 2005-04-07
Points: 0

thanks for your answers, both helped me a lot

Shannon :
I had to modify a little bit your example to reflect my pb. Then I realized I had
actually a JList+JScrollPane pb. My list is initially empty, when button is pressed
a new item is added to the list.

public class ListTest2 extends JFrame {

public ListTest2() {

final JList list = new JList( new DefaultListModel());

JPanel p = new JPanel();

GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
p.setLayout(gbl);

// half of the available space should be given
gbc.weightx = 0.5;
gbc.gridx = 0;

gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(list, gbc);

//p.add( new JScrollPane(list));
p.add( list);
gbc.gridx = 1;

JButton addButton = new JButton( "ADD");
addButton.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e) {
ListModel model = list.getModel();
((DefaultListModel)model).add( 0, "XX");
}
});
gbl.setConstraints(addButton, gbc);

p.add(addButton);
getContentPane().add(p);
}
}

1) without JScrollPane : initially JList is invisible (not nice, but for this demo it is ok).
Then when an item is added, the list's width become 50% of panel's width and remains like that even
when the frame is resized. That's fine.

2) with JScrollPane : initially JList is visible, but it's width isn't 50% of panel's width.
Then when an item is added, its width doesn't change as long as the frame is not resized.
When resized, it becomes the width of the displayed item.

Whereas JScrollPane+JTable is simple to use, it seems that JScrollPane+JList behaves differently.

Thomas:
I tried TableLayout and it solved my issue.
I will definitly also take a look at NaturalLayout.

Thanks a lot

shan-man
Offline
Joined: 2006-02-17
Points: 0

> thanks for your answers, both helped me a lot

No problem ;)

>
> Shannon :
> I had to modify a little bit your example to reflect
> my pb. Then I realized I had
> actually a JList+JScrollPane pb.

We can make it work for that too!

>
> 1) without JScrollPane : initially JList is invisible
> (not nice, but for this demo it is ok).
> Then when an item is added, the list's width become
> 50% of panel's width and remains like that even
> when the frame is resized. That's fine.

Interesting...I can take a look at that if you want, but since you said you want a JScrollPane, I've only looked at point #2.

By the way, I don't know if you noticed, but the way you have it now, it doesn't behave as you wanted for really long list values - the list becomes too large (more than 50%). You can fix that by putting back the code that I had that was overriding getPreferredSize on the list.

>
> 2) with JScrollPane : initially JList is visible, but
> it's width isn't 50% of panel's width.
> Then when an item is added, its width doesn't change
> as long as the frame is not resized.
> When resized, it becomes the width of the displayed
> item.

Take a look at this example. Both the scrollpane containing the list and the button will always have 50% of the width. One of the things you may have forgotten is that the constraints need to be set on the JScrollPane, not the list. Also, I found that overriding getPreferredSize on both components (scrollpane and button) to return a 0 width, allows for them to be completely controlled by the layout manager.

I can't say whether or not this is the BEST way to accomplish this, but it works and it's not too much code.

[code]
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class ListTest3 extends JFrame {
public ListTest3() {
final JList list = new JList( new DefaultListModel());

JPanel p = new JPanel();

GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();

p.setLayout(gbl);

// half of the available space should be given
gbc.weightx = 0.5;
gbc.gridx = 0;

gbc.fill = GridBagConstraints.HORIZONTAL;

JScrollPane sp = new JScrollPane(list) {
// override getPreferredSize so that the layout
// manager will fully control our width
public Dimension getPreferredSize() {
return new Dimension(0, super.getPreferredSize().height);
}
};

gbl.setConstraints(sp, gbc);

p.add( sp);
gbc.gridx = 1;

JButton addButton = new JButton( "ADD") {
// override getPreferredSize so that the layout
// manager will fully control our width
public Dimension getPreferredSize() {
return new Dimension(0, super.getPreferredSize().height);
}
};

addButton.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e) {
ListModel model = list.getModel();
((DefaultListModel)model).add( 0, "XX");
}
});

gbl.setConstraints(addButton, gbc);

p.add(addButton);
getContentPane().add(p);
}

public static void main(String[] args) {
ListTest3 lt = new ListTest3();
lt.setSize(400, 400);
lt.setVisible(true);
}
}
[/code]

Regards,
Shannon

zander
Offline
Joined: 2003-06-13
Points: 0

I would find it non-pleasing to create a list that would _always_ take 50% of the width; just taking preferred width would seem suffice. Naturally it should not make other text unreadable, and it should not 'jump around' when a new entry is entered. Both of which GridBag is known to do.

I suggest you try to find the TableLayout layouter which is capably of doing just what you need if you think I missed your point in the above paragraph.
Otherwise please try to use the NaturalLayout from the UICompiler package which can do this for you quite easily:
The layouter is in the http://uic.sf.net/tutorials/graphics.jar and the code would be:

[code]
import uic.layout.NaturalLayout;
import javax.swing.*;

public class MyWidget extends JPanel {
public MyWidget() {
NaturalLayout layout = new NaturalLayout(2, 1);
setLayout(layout);
layout.setSpacing(6);
layout.setMargin(11);

JList list = new JList( new String[] {"New Item", "New Item 2"});
JScrollPane scroller = new JScrollPane();
scroller.getViewport().add(list, null);
add(scroller, "0,0");
JPanel panel = new JPanel();
panel.setBackground(Color.RED);
add(panel, "1,0");
}
}
[/code]

If you like the layouter I suggest to take a look a the whole project since it can generate this and much more advanced stuff for you. http://uic.sf.net

shan-man
Offline
Joined: 2006-02-17
Points: 0

Hi,

Here's a little example that uses GridBagLayout to make a JList always be half the size of a panel. In this example, the JList is on the left half of the panel, but the example could be mofied to place it elsewhere. Hope this helps!

Shannon

[code]
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
* Example to show how GridBagLayout can be used
* to make a list always fill half of a panel.
*
* @author Shannon Hickey
*/
public class ListTest extends JFrame {
public ListTest() {
JList list = new JList(new Object[] {"One", "Two", "Three"});
JPanel p = new JPanel();

GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
p.setLayout(gbl);

// half of the available space should be given
gbc.weightx = 0.5;

gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(list, gbc);

p.add(list);

// a JLabel will be used to take the other half of the space
JLabel spacer = new JLabel();
gbl.setConstraints(spacer, gbc);

p.add(spacer);

getContentPane().add(p);
}

public static void main(String[] args) {
ListTest lt = new ListTest();
lt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lt.setSize(400, 400);
lt.setLocationRelativeTo(null);
lt.setVisible(true);
}
}
[/code]

shan-man
Offline
Joined: 2006-02-17
Points: 0

Hi again,

After writing that example, I re-read your post and realized that the approach I took is probably what you have already. It wasn't until I tried the list with a really long value that I saw it doesn't solve your problem. I see that the list ends up taking up more than half of the space. So, here's a revised version that addresses that.

It seems that the GridBagLayout was trying to give the list it's preferred width, regardless of whether or not that satisfied the constraints. In this second version, I've overridden getPreferredSize to return a 0 preferred width. That way, the GridBagLayout takes full control over how much width it is given.

Hopefully this one does the trick for you.

[code]
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
* Example to show how GridBagLayout can be used
* to make a list always fill half of a panel.
* This version addresses the issue where lists
* with long values end up taking more width
* than specified in the GridBagConstraints.
*
* @author Shannon Hickey
*/
public class ListTest2 extends JFrame {
public ListTest2() {
String longValue = "Really really really really long value";

JList list = new JList(new Object[] {"One", "Two", "Three", longValue}) {

// overriding getPreferredSize allows the component to get smaller
public Dimension getPreferredSize() {
return new Dimension(0, super.getPreferredSize().height);
}

};

JPanel p = new JPanel();

GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
p.setLayout(gbl);

// half of the available space should be given
gbc.weightx = 0.5;
gbc.gridx = 0;

gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(list, gbc);

p.add(list);

gbc.gridx = 1;

// a JLabel will be used to take the other half of the space
JLabel spacer = new JLabel();
gbl.setConstraints(spacer, gbc);

p.add(spacer);

getContentPane().add(p);
}

public static void main(String[] args) {
ListTest2 lt = new ListTest2();
lt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lt.setSize(400, 400);
lt.setLocationRelativeTo(null);
lt.setVisible(true);
}
}
[/code]