Reputation: 453
I'm using a JTable on a project. I want the table to auto-resize all columns to the same size, and at the same time, to fill the width of the containing JScrollPane.
I can't just set a preferred width to a fixed value, because when the user will resize the frame, I want all the columns being resized to the same size, but with the constraint that it must still fill 100% of the JScrollPane.
For instance, if the JScrollPane has a width of 1000, and I've got 10 columns, I'd like the columns to each have a size of 100. If the JScrollPane is then shrinked to 500, I'd like the columns to resize to 50 each.
For now, I just set JTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF)
and here's the result :
How can I simply achieve that ?
Thanks.
Upvotes: 4
Views: 7606
Reputation: 626
I used this in my last project!
addComponentListener(new ComponentListener() {
@Override public void componentShown(ComponentEvent e) {}
@Override public void componentMoved(ComponentEvent e) {}
@Override public void componentHidden(ComponentEvent e) {}
@Override
public void componentResized(ComponentEvent e) {
int w = table.getWidth() / table.getColumnCount();
for(int i = 0; i < table.getColumnCount(); i++) {
table.getColumn(i).setPreferredWidth(w);
}
}
});
Upvotes: 0
Reputation: 347194
You need some way to update the column model when the table changes size.
This basic example uses the invaldiate
method to update it's column model. It also sets the columns as "not" resizable.
This also overrides the tables getScrollableTracksViewportWidth
method to ensure that the table automatically fills the horizontal space. This does mean that it will never display a horizontal scroll bar though.
public class SpringTable extends JTable {
public SpringTable(TableModel dm) {
super(dm);
setAutoResizeMode(AUTO_RESIZE_OFF);
}
public SpringTable() {
setAutoResizeMode(AUTO_RESIZE_OFF);
}
@Override
public void doLayout() {
int width = getWidth();
int columnCount = getColumnCount();
int columnSize = width / columnCount;
for (int index = 0; index < columnCount; index++) {
TableColumn column = getColumnModel().getColumn(index);
column.setResizable(false);
column.setPreferredWidth(width);
}
super.doLayout();
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
}
It may be better to use doLayout
instead on invalidate
, but you should have a play and see what meets your needs
Running example
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
public class TestJTable {
public static void main(String[] args) {
new TestJTable();
}
public TestJTable() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
List<Pet> pets = new ArrayList<>(25);
pets.add(new Pet("Tyrannosauridae", "TYRANNOSAURUS", 20, 35));
pets.add(new Pet("Dromaeosauridae", "VELOCIRAPTOR", 45, 90));
pets.add(new Pet("Ceratopsidae", "TRICERATOPS", 15, 30));
pets.add(new Pet("Stegosauridae", "STEGOSAURUS", 22, 25));
pets.add(new Pet("Titanosauridae", "MALAWISAURUS", 22, 25));
pets.add(new Pet("Compsognathidae", "COMPSOGNATHUS", 8, 25));
pets.add(new Pet("Brachiosauridae", "BRACHIOSAURUS", 8, 25));
pets.add(new Pet("Diplodocidae", "DIPLODOCUS", 8, 25));
final PetTableModel model = new PetTableModel(pets);
final JTable table = new SpringTable(model);
InputMap im = table.getInputMap(JTable.WHEN_FOCUSED);
ActionMap am = table.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
am.put("delete", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
int[] indicies = table.getSelectedRows();
int[] mapped = new int[indicies.length];
for (int index = 0; index < indicies.length; index++) {
mapped[index] = table.convertRowIndexToModel(indicies[index]);
}
model.removePets(mapped);
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SpringTable extends JTable {
public SpringTable(TableModel dm) {
super(dm);
setAutoResizeMode(AUTO_RESIZE_OFF);
}
public SpringTable() {
setAutoResizeMode(AUTO_RESIZE_OFF);
}
@Override
public void doLayout() {
int width = getWidth();
int columnCount = getColumnCount();
int columnSize = width / columnCount;
for (int index = 0; index < columnCount; index++) {
TableColumn column = getColumnModel().getColumn(index);
column.setResizable(false);
column.setPreferredWidth(width);
}
super.doLayout();
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
}
public class PetTableModel extends AbstractTableModel {
private List<Pet> pets;
public PetTableModel() {
pets = new ArrayList<>(25);
}
public PetTableModel(List<Pet> pets) {
this.pets = pets;
}
@Override
public int getRowCount() {
return pets.size();
}
public void removePets(int... indicies) {
List<Pet> old = new ArrayList<>(indicies.length);
for (int index : indicies) {
old.add(pets.get(index));
}
for (Pet pet : old) {
int index = pets.indexOf(pet);
pets.remove(pet);
fireTableRowsDeleted(index, index);
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
Class clazz = String.class;
switch (columnIndex) {
case 2:
case 3:
clazz = Float.class;
}
return clazz;
}
@Override
public String getColumnName(int column) {
String name = "??";
switch (column) {
case 0:
name = "Breed";
break;
case 1:
name = "Category";
break;
case 2:
name = "Buy Price";
break;
case 3:
name = "Sell Price";
break;
}
return name;
}
@Override
public int getColumnCount() {
return 4;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Pet pet = pets.get(rowIndex);
Object value = null;
switch (columnIndex) {
case 0:
value = pet.getBreed();
break;
case 1:
value = pet.getCategory();
break;
case 2:
value = pet.getBuyPrice();
break;
case 3:
value = pet.getSellPrice();
break;
}
return value;
}
public void add(Pet pet) {
pets.add(pet);
fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);
}
}
public class Pet {
private String breed;
private String category;
private float buyPrice;
private float sellPrice;
public Pet(String breed, String category, float buyPrice, float sellPrice) {
this.breed = breed;
this.category = category;
this.buyPrice = buyPrice;
this.sellPrice = sellPrice;
}
public String getBreed() {
return breed;
}
public float getBuyPrice() {
return buyPrice;
}
public String getCategory() {
return category;
}
public float getSellPrice() {
return sellPrice;
}
}
}
Upvotes: 3
Reputation: 324108
As best as I can tell the default behaviour (using JDK7 on Windows 7) of a JTable is to equally size each column when the table size is changed. This seems to work as long as you haven't set a preferred width on the table column.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class TestJTable {
public static void main(String[] args) {
new TestJTable();
}
public TestJTable() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
String[] columnNames = {"Column1", "a", "a long long column name", "column4"};
DefaultTableModel model = new DefaultTableModel(columnNames, 5);
final JTable table = new JTable(model);
JButton button = new JButton("Display Column Widths");
button.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
int columnCount = table.getColumnCount();
for (int index = 0; index < columnCount; index++)
{
TableColumn column = table.getColumnModel().getColumn(index);
System.out.print(column.getWidth() + ", ");
}
System.out.println();
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Upvotes: 1
Reputation:
After resize the JTable, you can get the new width (JTable.getWidth()), divide by 10 (making the necessary adjustments to get an integer result), then set the width of each column manually (see if this helps ).
Upvotes: 0