Related
I'm trying to create a dynamic JTable in Java Swing where users can add/delete rows and columns as they want. Everything is good, except for deleting the column. I've been at this for hours now and I can't figure out how to completely erase a column and its values.
There are removeColumn(int) methods in the classes, but they only hide the column from view. I've also searched and found this answer, but when I try to create the CustomTableModel class and extend DefaultTableModel, I just get a ClassCastException.
Adding a column
Determine the new index of the column (how you do this is up to you)
Determine the new values for each row/column - you could also just as easily set the values to null to start with
Update the row data in the model
Update the column data in the model (ie columnCount and columnName)
Trigger a TableModelEvent.HEADER_ROW event so that the JTable updates itself with the new data
Removing a column
Determine the column index to be removed
Remove the column data for each row
Update the column data in the model (ie columnCount and columnName)
Trigger a TableModelEvent.HEADER_ROW event so that the JTable updates itself with the new data
Runnable example
This is a basic example of the concept. Personally I prefer to manage my data via POJOs (which is here the idea of "hiding columns" would be more practical, but that might not always be possible
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private MutableTableModel model;
private JTable table;
public TestPane() {
setLayout(new BorderLayout());
JButton addColumnButton = new JButton("Add column");
JButton removeColumnButton = new JButton("Remove column");
addColumnButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
List<Object> rows = new ArrayList<>(100);
for (int row = 0; row < 100; row++) {
rows.add(randomString());
}
String columnName = JOptionPane.showInputDialog(TestPane.this, "Column name");
if (columnName == null || columnName.isBlank()) {
columnName = randomString();
}
int columnIndex = table.getSelectedColumn();
if (columnIndex < 0) {
model.addColumn(columnName, rows);
} else {
model.addColumn(columnName, rows, columnIndex + 1);
}
}
});
removeColumnButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int columnIndex = table.getSelectedColumn();
if (columnIndex < 0) {
JOptionPane.showMessageDialog(TestPane.this, "Now column selected");
} else {
model.removeColumn(columnIndex);
}
}
});
JPanel actionPanels = new JPanel(new GridBagLayout());
actionPanels.add(addColumnButton);
actionPanels.add(removeColumnButton);
add(actionPanels, BorderLayout.SOUTH);
String[] columnNames = new String[]{"One", "Two", "Three", "Four", "Five"};
List<List<Object>> rows = new ArrayList<>(100);
for (int row = 0; row < 100; row++) {
List<Object> rowData = new ArrayList<>(columnNames.length);
for (int col = 0; col < columnNames.length; col++) {
rowData.add(randomString());
}
rows.add(rowData);
}
model = new MutableTableModel(Arrays.asList(columnNames), rows);
table = new JTable(model);
add(new JScrollPane(table));
}
private Random random = new Random();
protected String randomString() {
int leftLimit = 48; // numeral '0'
int rightLimit = 122; // letter 'z'
int targetStringLength = 10;
String generatedString = random.ints(leftLimit, rightLimit + 1)
.filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
.limit(targetStringLength)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
return generatedString;
}
}
public class MutableTableModel extends AbstractTableModel {
private ArrayList<List<Object>> rows = new ArrayList<>(32);
private ArrayList<String> columnNames = new ArrayList<>(8);
public MutableTableModel() {
}
public MutableTableModel(List<String> columnNames, List<List<Object>> rows) {
this.columnNames = new ArrayList<>(columnNames);
this.rows = new ArrayList<>(rows);
}
public void addColumn(String name) {
addColumn(name, columnNames.size() - 1);
}
public void addColumn(String name, int columnIndex) {
columnIndex = Math.max(0, Math.min(columnIndex, columnNames.size()));
int rowCount = getRowCount();
List<Object> rows = new ArrayList<>(rowCount);
for (int row = 0; row < rowCount; row++) {
rows.add(null);
}
addColumn(name, rows, columnIndex);
}
public void addColumn(String name, List<Object> rows) {
addColumn(name, rows, columnNames.size());
}
public void addColumn(String name, List<Object> newRows, int columnIndex) {
columnIndex = Math.max(0, Math.min(columnIndex, columnNames.size()));
columnNames.add(columnIndex, name);
int rowCount = getRowCount();
for (int row = 0; row < rowCount; row++) {
List<Object> rowData = rows.get(row);
Object value = null;
if (row < newRows.size()) {
value = newRows.get(row);
}
rowData.add(columnIndex, value);
}
fireTableStructureChanged();
}
public void removeColumn(int columnIndex) {
if (columnIndex < 0 || columnIndex >= columnNames.size()) {
return;
}
int rowCount = getRowCount();
for (int row = 0; row < rowCount; row++) {
List<Object> rowData = rows.get(row);
rowData.remove(columnIndex);
}
columnNames.remove(columnIndex);
fireTableStructureChanged();
}
#Override
public int getRowCount() {
return rows.size();
}
#Override
public int getColumnCount() {
return columnNames.size();
}
#Override
public String getColumnName(int column) {
if (column >= columnNames.size()) {
return super.getColumnName(column);
}
return columnNames.get(column);
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return rows.get(rowIndex).get(columnIndex);
}
}
}
Thanks to camickr for knocking my head back in place, I really just had to set the model to CustomTableModel so I could cast it back using getModel() as well. It now works using the answer in here. If you're using NetBeans, be sure to edit the autogenerated code yourself and change...
contentTable.setModel(new TableModel(
new Object [][] {
},
new String [] {
}
));
to
contentTable.setModel(new CustomTableModel(
new Object [][] {
},
new String [] {
}
));
I have JTable with some rows. I want when move one row with mouse(drag and drop) that row to move together with mouse and table rows to be reorder when mouse move(like moving JTable's columns).
This jsfiddle is exactly what i want but i have to do it in java swing(or gif image below. Example is from here but I can't understand it).
My TransferHandler :
public class TableRowTransferHandler extends TransferHandler {
private final DataFlavor localObjectFlavor = new ActivationDataFlavor(Integer.class, "application/x-java-Integer;class=java.lang.Integer", "Integer Row Index");
private JTable table = null;
private static final Logger logger = Logger.getLogger(TableRowTransferHandler.class.getName());
public TableRowTransferHandler(JTable table) {
this.table = table;
}
#Override
protected Transferable createTransferable(JComponent c) {
assert (c == table);
return new DataHandler(table.getSelectedRow(), localObjectFlavor.getMimeType());
}
#Override
public boolean canImport(TransferHandler.TransferSupport info) {
boolean b = info.getComponent() == table && info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
table.setCursor(b ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop);
return b;
}
#Override
public int getSourceActions(JComponent c) {
return TransferHandler.COPY_OR_MOVE;
}
#Override
public boolean importData(TransferHandler.TransferSupport info) {
JTable target = (JTable) info.getComponent();
JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
int index = dl.getRow();
int max = table.getModel().getRowCount();
if (index < 0 || index > max) {
index = max;
}
target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
try {
Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
if (rowFrom != -1 && rowFrom != index) {
((Reorderable) table.getModel()).reorder(rowFrom, index);
if (index > rowFrom) {
index--;
}
target.getSelectionModel().addSelectionInterval(index, index);
return true;
}
} catch (UnsupportedFlavorException | IOException e) {
e.printStackTrace();
logger.log(Level.SEVERE, null, e);
}
return false;
}
#Override
protected void exportDone(JComponent c, Transferable t, int act) {
if ((act == TransferHandler.MOVE) || (act == TransferHandler.NONE)) {
table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
That is a simple settings that i use to JTable:
childrenTable.setDragEnabled(true);
childrenTable.setDropMode(DropMode.INSERT);
childrenTable.setTransferHandler(new TableRowTransferHandler(childrenTable));
childrenTable.setRowSelectionAllowed(true);
childrenTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
At the moment when you move row with mouse between rows only have one bold line(Like this in red ellipse below in image). If it is impossible to do rows to move like this, i want this bold line to appear to whole row (not only in one cell).
Read the section from the Swing tutorial on Drag and Drop for the basics.
Here is some old code I found somewhere on the web with a custom TransferHandler to support a JTable:
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.IOException;
public class DnD_Demo extends JFrame {
public DnD_Demo() {
setTitle("DnD Demo (Version 3)");
JTextArea tips = new JTextArea("1. Select a row in Table A. " +
"Press the row again and drag. \n " +
"As you drag the cursor icon over Table B, the row that is currently under the cursor highlights " +
"- the new data will be inserted after the selected row. \n " +
"Drop the row onto Table B. Note that the row has been removed from Table A, " +
"and now appears in Table B. \n" +
"2. Select two rows from Table A and drop onto Table B. " +
"Now there are two new rows in Table B. ");
tips.setEditable(false);
tips.setBackground(new Color(255,255,204));
tips.setBorder(new LineBorder(Color.orange,5));
getContentPane().add(tips,BorderLayout.NORTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout(2,1));
panel.add(createTable("Table A"));
panel.add(createTable("Table B"));
getContentPane().add(panel,BorderLayout.CENTER);
pack();
}
private JPanel createTable(String tableId) {
DefaultTableModel model = new DefaultTableModel();
model.addColumn("Column 0");
model.addColumn("Column 1");
model.addColumn("Column 2");
model.addColumn("Column 3");
model.addRow(new String[]{tableId+" 00", tableId+" 01", tableId+" 02", tableId+" 03"});
model.addRow(new String[]{tableId+" 10", tableId+" 11", tableId+" 12", tableId+" 13"});
model.addRow(new String[]{tableId+" 20", tableId+" 21", tableId+" 22", tableId+" 23"});
model.addRow(new String[]{tableId+" 30", tableId+" 31", tableId+" 32", tableId+" 33"});
JTable table = new JTable(model);
table.getTableHeader().setReorderingAllowed(false);
table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(new Dimension(400,100));
table.setDragEnabled(true);
table.setTransferHandler(new TableTransferHandler());
JPanel panel = new JPanel();
panel.add(scrollPane);
panel.setBorder(BorderFactory.createTitledBorder(tableId));
return panel;
}
public static void main(String[] args) {
new DnD_Demo().setVisible(true);
}
abstract class StringTransferHandler extends TransferHandler {
protected abstract String exportString(JComponent c);
protected abstract void importString(JComponent c, String str);
protected abstract void cleanup(JComponent c, boolean remove);
protected Transferable createTransferable(JComponent c) {
return new StringSelection(exportString(c));
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
public boolean importData(JComponent c, Transferable t) {
if (canImport(c, t.getTransferDataFlavors())) {
try {
String str = (String)t.getTransferData(DataFlavor.stringFlavor);
importString(c, str);
return true;
} catch (UnsupportedFlavorException ufe) {
} catch (IOException ioe) {
}
}
return false;
}
protected void exportDone(JComponent c, Transferable data, int action) {
cleanup(c, action == MOVE);
}
public boolean canImport(JComponent c, DataFlavor[] flavors) {
for (int i = 0; i < flavors.length; i++) {
if (DataFlavor.stringFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
}
class TableTransferHandler extends StringTransferHandler {
public JTable target;
public int[] rows = null;
public int addIndex = -1; //Location where items were added
public int addCount = 0; //Number of items added.
protected String exportString(JComponent c) {
JTable table = (JTable)c;
rows = table.getSelectedRows();
int colCount = table.getColumnCount();
StringBuffer buff = new StringBuffer();
for (int i = 0; i < rows.length; i++) {
for (int j = 0; j < colCount; j++) {
Object val = table.getValueAt(rows[i], j);
buff.append(val == null ? "" : val.toString());
if (j != colCount - 1) {
buff.append(",");
}
}
if (i != rows.length - 1) {
buff.append("\n");
}
}
return buff.toString();
}
protected void importString(JComponent c, String str) {
target = (JTable)c;
DefaultTableModel model = (DefaultTableModel)target.getModel();
int index = target.getSelectedRow();
//Prevent the user from dropping data back on itself.
//For example, if the user is moving rows #4,#5,#6 and #7 and
//attempts to insert the rows after row #5, this would
//be problematic when removing the original rows.
//So this is not allowed.
if (rows != null && index >= rows[0] - 1 &&
index <= rows[rows.length - 1]) {
rows = null;
return;
}
int max = model.getRowCount();
if (index < 0) {
index = max;
} else {
index++;
if (index > max) {
index = max;
}
}
addIndex = index;
String[] values = str.split("\n");
addCount = values.length;
int colCount = target.getColumnCount();
for (int i = 0; i < values.length ; i++) {
model.insertRow(index++, values[i].split(","));
}
//If we are moving items around in the same table, we
//need to adjust the rows accordingly, since those
//after the insertion point have moved.
if (rows!= null && addCount > 0) {
for (int i = 0; i < rows.length; i++) {
if (rows[i] > addIndex) {
rows[i] += addCount;
}
}
}
}
protected void cleanup(JComponent c, boolean remove) {
JTable source = (JTable)c;
if (remove && rows != null) {
DefaultTableModel model =
(DefaultTableModel)source.getModel();
for (int i = rows.length - 1; i >= 0; i--) {
model.removeRow(rows[i]);
}
}
rows = null;
addCount = 0;
addIndex = -1;
}
}
}
I think that ListTransferHandler.java for item swapping of JList in the Swing tutorial will be also helpful.
Here is an example that I modified ListTransferHandler for JTable:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import java.util.List;
import javax.activation.*;
import javax.swing.*;
import javax.swing.table.*;
public final class TableRowsDnDTest {
private final TransferHandler handler = new TableRowTransferHandler();
private final String[] columnNames = {"String", "Integer", "Boolean"};
private final Object[][] data = {
{"AAA", 12, true}, {"aaa", 1, false},
{"BBB", 13, true}, {"bbb", 2, false},
{"CCC", 15, true}, {"ccc", 3, false},
{"DDD", 17, true}, {"ddd", 4, false},
{"EEE", 18, true}, {"eee", 5, false},
{"FFF", 19, true}, {"fff", 6, false},
{"GGG", 92, true}, {"ggg", 0, false}
};
private final TableModel model = new DefaultTableModel(data, columnNames) {
#Override public Class<?> getColumnClass(int column) {
switch (column) {
case 0:
return String.class;
case 1:
return Number.class;
case 2:
return Boolean.class;
default:
return super.getColumnClass(column);
}
}
};
private final JTable table = new JTable(model);
public JComponent makeUI() {
table.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setTransferHandler(handler);
table.setDropMode(DropMode.INSERT_ROWS);
table.setDragEnabled(true);
table.setFillsViewportHeight(true);
//table.setAutoCreateRowSorter(true); //XXX
//Disable row Cut, Copy, Paste
ActionMap map = table.getActionMap();
Action dummy = new AbstractAction() {
#Override public void actionPerformed(ActionEvent e) { /* Dummy action */ }
};
map.put(TransferHandler.getCutAction().getValue(Action.NAME), dummy);
map.put(TransferHandler.getCopyAction().getValue(Action.NAME), dummy);
map.put(TransferHandler.getPasteAction().getValue(Action.NAME), dummy);
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(table));
p.setBorder(BorderFactory.createTitledBorder("Drag & Drop JTable"));
return p;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TableRowsDnDTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
//Demo - BasicDnD (Drag and Drop and Data Transfer) https://docs.oracle.com/javase/tutorial/uiswing/dnd/basicdemo.html
//Demo - DropDemo (Drag and Drop and Data Transfer) https://docs.oracle.com/javase/tutorial/uiswing/dnd/dropmodedemo.html
//#see https://docs.oracle.com/javase/tutorial/uiswing/examples/dnd/DropDemoProject/src/dnd/ListTransferHandler.java
//#see https://github.com/aterai/java-swing-tips/blob/master/DnDReorderTable/src/java/example/TableRowsDnDTest.java
class TableRowTransferHandler extends TransferHandler {
private final DataFlavor localObjectFlavor;
private int[] indices;
private int addIndex = -1; //Location where items were added
private int addCount; //Number of items added.
protected TableRowTransferHandler() {
super();
localObjectFlavor = new ActivationDataFlavor(Object[].class, DataFlavor.javaJVMLocalObjectMimeType, "Array of items");
}
#Override protected Transferable createTransferable(JComponent c) {
JTable table = (JTable) c;
DefaultTableModel model = (DefaultTableModel) table.getModel();
List<Object> list = new ArrayList<>();
indices = table.getSelectedRows();
for (int i : indices) {
list.add(model.getDataVector().get(i));
}
Object[] transferedObjects = list.toArray();
return new DataHandler(transferedObjects, localObjectFlavor.getMimeType());
}
#Override public boolean canImport(TransferHandler.TransferSupport info) {
JTable table = (JTable) info.getComponent();
boolean isDropable = info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
table.setCursor(isDropable ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop);
return isDropable;
}
#Override public int getSourceActions(JComponent c) {
return TransferHandler.MOVE;
}
#Override public boolean importData(TransferHandler.TransferSupport info) {
if (!canImport(info)) {
return false;
}
TransferHandler.DropLocation tdl = info.getDropLocation();
if (!(tdl instanceof JTable.DropLocation)) {
return false;
}
JTable.DropLocation dl = (JTable.DropLocation) tdl;
JTable target = (JTable) info.getComponent();
DefaultTableModel model = (DefaultTableModel) target.getModel();
int index = dl.getRow();
int max = model.getRowCount();
if (index < 0 || index > max) {
index = max;
}
addIndex = index;
target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
try {
Object[] values = (Object[]) info.getTransferable().getTransferData(localObjectFlavor);
addCount = values.length;
for (int i = 0; i < values.length; i++) {
int idx = index++;
model.insertRow(idx, (Vector) values[i]);
target.getSelectionModel().addSelectionInterval(idx, idx);
}
return true;
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
return false;
}
#Override protected void exportDone(JComponent c, Transferable data, int action) {
cleanup(c, action == TransferHandler.MOVE);
}
//If the remove argument is true, the drop has been
//successful and it's time to remove the selected items
//from the list. If the remove argument is false, it
//was a Copy operation and the original list is left
//intact.
protected void cleanup(JComponent c, boolean remove) {
if (remove && indices != null) {
c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
DefaultTableModel model = (DefaultTableModel)((JTable) c).getModel();
//If we are moving items around in the same list, we
//need to adjust the indices accordingly, since those
//after the insertion point have moved.
if (addCount > 0) {
for (int i = 0; i < indices.length; i++) {
if (indices[i] >= addIndex) {
indices[i] += addCount;
}
}
}
for (int i = indices.length - 1; i >= 0; i--) {
model.removeRow(indices[i]);
}
}
indices = null;
addCount = 0;
addIndex = -1;
}
}
I have been thinking a lot to solve this mistake. But unfortunately I came to final cnclusion that I need help of professionals.
Please, copy,paste this code to see issue:
public class DateFormatDemo extends JFrame
{
private JTable dataSearchResultTable;
public DateFormatDemo()
{
JButton updateTable = new JButton("Update table");
updateTable.setMaximumSize(updateTable.getPreferredSize());
updateTable.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
updateMyTableModel();
}
});
JPanel panel = new JPanel(new GridLayout(2, 1, 5, 10));
panel.setPreferredSize(new Dimension(500, 300));
panel.add(new JScrollPane(initDataSearchResultTable()));
panel.add(updateTable);
super.getContentPane().add(panel);
super.pack();
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
super.setVisible(true);
}
private JTable initDataSearchResultTable()
{
dataSearchResultTable = new JTable();
// dataSearchResultTable.setAutoCreateColumnsFromModel(false);
dataSearchResultTable.setSelectionBackground(new Color(0xaaaaff));
dataSearchResultTable.setFillsViewportHeight(true);
dataSearchResultTable.setRowSelectionAllowed(true);
dataSearchResultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
dataSearchResultTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
return dataSearchResultTable;
}
void updateMyTableModel()
{
TableModel tableModel = dataSearchResultTable.getModel();
TableColumnModel columnModel = dataSearchResultTable.getColumnModel();
if (tableModel instanceof MyTableModel) {
((MyTableModel) tableModel).updateModel();
this.initColumnWidths(tableModel, columnModel);
} else {
tableModel = new MyTableModel();
dataSearchResultTable.setModel(tableModel);
this.makeColumnsNotResizable(columnModel);
this.initColumnWidths(tableModel, columnModel);
}
}
private void makeColumnsNotResizable(TableColumnModel columnModel)
{
for (int i = 0; i < columnModel.getColumnCount(); i++) {
if (i == 0 || i == 1) {
columnModel.getColumn(i).setResizable(false);
}
}
}
private void initColumnWidths(TableModel tableModel, TableColumnModel columnModel)
{
TableColumn column = null;
Component comp = null;
int cellWidth = 0;
int headerWidth = 0;
TableCellRenderer headerRenderer = dataSearchResultTable.getTableHeader().getDefaultRenderer();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
column = columnModel.getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(null, column.getHeaderValue(), false, false, -1, 0);
headerWidth = comp.getPreferredSize().width;
Class<?> columnClass = tableModel.getColumnClass(i);
for (int j = 0; j < tableModel.getRowCount(); j++) {
comp = dataSearchResultTable.getDefaultRenderer(columnClass).getTableCellRendererComponent(
dataSearchResultTable, tableModel.getValueAt(j, i), false, false, j, i);
int width = comp.getPreferredSize().width;
// we cache width of first row. And compare widths of next
// rows with width of first.
// If some row has greater width it becomes width of whole
// row(unless header has greater width)
if (cellWidth < width || j == 0) {
cellWidth = width;
}
}
System.out
.println("columnClass=" + columnClass + ",headerWidth=" + headerWidth + ",cellWidth=" + cellWidth);
if (headerWidth > cellWidth) {
TableCellRenderer centeredRenderer = dataSearchResultTable.getDefaultRenderer(columnClass);
if (centeredRenderer instanceof DefaultTableCellRenderer) {
((DefaultTableCellRenderer) centeredRenderer).setHorizontalAlignment(SwingConstants.CENTER);
column.setCellRenderer(centeredRenderer);
column.setPreferredWidth(headerWidth);
}
} else {
column.setPreferredWidth(cellWidth + 5);
}
}
}
class MyTableModel extends AbstractTableModel
{
private String[] columnNames = { "First Name", "Last Name", "Timestamp", "Number", "Vegetarian" };
private Object[][] data = new Object[5][];
void updateModel()
{
data = new Object[][] {
{ "Vova", "KipokKipokKipokKipok", "2013-04-12 11:20:41", new Integer(5), new Boolean(true) },
{ "Olia", "Duo", "2010-01-11 11:11:41", new Integer(3), new Boolean(false) },
{ "Oksana", "Stack", "2012-04-12 11:20:41", new Integer(2), new Boolean(false) },
{ "Petro", "White", "2010-04-12 11:20:21", new Integer(20), new Boolean(true) },
{ "Ivan", "Brown", "2011-04-11 11:20:41", new Integer(10), new Boolean(true) } };
fireTableDataChanged();
}
public int getColumnCount()
{
return columnNames.length;
}
public int getRowCount()
{
return data.length;
}
public String getColumnName(int col)
{
return columnNames[col];
}
public Object getValueAt(int row, int col)
{
if (data.length > 0 && data[0] != null) {
return data[row][col];
}
return null;
}
/*
* JTable uses this method to determine the default renderer/ editor for
* each cell. If we didn't implement this method, then the last column
* would contain text ("true"/"false"), rather than a check box.
*/
public Class getColumnClass(int c)
{
Object valueAt = getValueAt(0, c);
return valueAt == null ? Object.class : valueAt.getClass();
}
/*
* Don't need to implement this method unless your table's editable.
*/
public boolean isCellEditable(int row, int col)
{
// Note that the data/cell address is constant,
// no matter where the cell appears onscreen.
if (col < 2) {
return false;
} else {
return true;
}
}
/*
* Don't need to implement this method unless your table's data can
* change.
*/
public void setValueAt(Object value, int row, int col)
{
if (data.length > 0 && data[0] != null) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
}
public static void main(String[] args) throws ParseException
{
new DateFormatDemo();
}
}
Now please click twice on that big button called 'Update Table'. As you see column that should display checkbox as it holds boolean values do not do that but instead displays String true or false.
This code emulates my real workflow.
So, how to update tablemodel to have boolean columns with checkbozes.
Thanks!
take this as simple start point
import java.awt.*;
import java.util.Random;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class Forum implements ListSelectionListener {
private JFrame frame = new JFrame("Frame");
private JPanel fatherCenter = new JPanel();
private JScrollPane tableScroll = new JScrollPane();
private MyTableModel tableModel;
private JTable dialogTable;
private ListSelectionModel lsDialog;
private Color clr;
private Color clr1;
private void addData() {
Runnable doRun1 = new Runnable() {
#Override
public void run() {
tableModel.resetTable();
Vector<String> tbl = new Vector<String>();
Vector<Object> tbl1 = new Vector<Object>();
Random rnd = new Random();
tbl.add("Integer");
tbl.add("Double");
tbl.add("Boolean");
tbl.add("Boolean");
tbl.add("String");
tableModel.setColumnNames(tbl);
for (int row = 0; row < 30; row++) {
tbl1 = null;
tbl1 = new Vector<Object>();
tbl1.addElement(row + 1);
tbl1.addElement(rnd.nextInt(25) + 3.14);
tbl1.addElement((row % 3 == 0) ? false : true);
tbl1.addElement((row % 5 == 0) ? false : true);
if (row % 7 == 0) {
tbl1.add(("Canc"));
} else if (row % 6 == 0) {
tbl1.add(("Del"));
} else {
tbl1.add(("New"));
}
tableModel.addRow(tbl1);
}
addTableListener();
}
};
SwingUtilities.invokeLater(doRun1);
}
private void addTableListener() {
tableModel.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent tme) {
if (tme.getType() == TableModelEvent.UPDATE) {
System.out.println("");
System.out.println("Cell " + tme.getFirstRow() + ", "
+ tme.getColumn() + " changed. The new value: "
+ tableModel.getValueAt(tme.getFirstRow(),
tme.getColumn()));
}
}
});
}
#Override
public void valueChanged(ListSelectionEvent le) {
int row = dialogTable.getSelectedRow();
int col = dialogTable.getSelectedColumn();
String str = "Selected Row(s): ";
int[] rows = dialogTable.getSelectedRows();
for (int i = 0; i < rows.length; i++) {
str += rows[i] + " ";
}
str += "Selected Column(s): ";
int[] cols = dialogTable.getSelectedColumns();
for (int i = 0; i < cols.length; i++) {
str += cols[i] + " ";
}
str += "Selected Cell: " + dialogTable.getSelectedRow() + ", " + dialogTable.getSelectedColumn();
System.out.println(str);
Object value = dialogTable.getValueAt(row, col);
System.out.println(String.valueOf(value));
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Forum osFrame = new Forum();
}
});
}
public Forum() {
tableModel = new MyTableModel();
dialogTable = new JTable(tableModel) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) comp;//for Custom JComponent
if (!isRowSelected(row)) {
int modelRow = convertRowIndexToModel(row);
boolean type = (Boolean) getModel().getValueAt(modelRow, 2);
boolean type1 = (Boolean) getModel().getValueAt(modelRow, 3);
comp.setForeground(Color.black);
if ((type) && (!type1)) {
comp.setBackground(clr1);
} else if ((!type) && (type1)) {
comp.setBackground(Color.orange);
} else if ((!type) || (!type1)) {
comp.setBackground(Color.red);
} else {
comp.setBackground(row % 2 == 0 ? getBackground() : getBackground().darker());
}
dialogTable.convertRowIndexToView(0);
} else {
comp.setForeground(Color.blue);
}
if (!isCellEditable(row, column)) {
comp.setForeground(Color.red);
comp.setBackground(Color.magenta);
}
return comp;
}
};
tableScroll = new JScrollPane(dialogTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tableScroll.setBorder(null);
dialogTable.getTableHeader().setReorderingAllowed(false);
dialogTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lsDialog = dialogTable.getSelectionModel();
dialogTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
dialogTable.setRowHeight(20);
dialogTable.setRowMargin(2);
dialogTable.setPreferredScrollableViewportSize(dialogTable.getPreferredSize());
ListSelectionModel rowSelMod = dialogTable.getSelectionModel();
//ListSelectionModel colSelMod = dialogTable.getColumnModel().getSelectionModel();
rowSelMod.addListSelectionListener(this);
//colSelMod.addListSelectionListener(this);
fatherCenter = new JPanel();
fatherCenter.setLayout(new BorderLayout(10, 10));
fatherCenter.add(tableScroll, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout(10, 10));
frame.add(fatherCenter);
frame.setPreferredSize(new Dimension(400, 660));
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
addData();
}
private class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private Vector<Vector<Object>> _data;
private Vector<String> _colNames;
private boolean[] _columnsVisible = {true, true, true, true, true};
public MyTableModel() {
_colNames = new Vector<String>();
_data = new Vector<Vector<Object>>();
}
public MyTableModel(Vector<String> colnames) {
_colNames = colnames;
_data = new Vector<Vector<Object>>();
}
public void resetTable() {
_colNames.removeAllElements();
_data.removeAllElements();
}
public void setColumnNames(Vector<String> colNames) {
_colNames = colNames;
fireTableStructureChanged();
}
public void addRow(Vector<Object> data) {
_data.add(data);
fireTableRowsInserted(_data.size() - 1, _data.size() - 1);
}
public void removeRowAt(int row) {
_data.removeElementAt(row);
fireTableRowsDeleted(row - 1, _data.size() - 1);
}
#Override
public int getColumnCount() {
return _colNames.size();
}
#Override
public Class<?> getColumnClass(int colNum) {
switch (colNum) {
case 0:
return Integer.class;
case 1:
return Double.class;
case 2:
return Boolean.class;
case 3:
return Boolean.class;
default:
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int colNum) {
switch (colNum) {
case 2:
return false;
default:
return true;
}
}
#Override
public String getColumnName(int colNum) {
return _colNames.get(colNum);
}
#Override
public int getRowCount() {
return _data.size();
}
#Override
public Object getValueAt(int row, int col) {
Vector<Object> value = _data.get(row);
return value.get(col);
}
#Override
public void setValueAt(Object newVal, int row, int col) {
Vector<Object> aRow = _data.elementAt(row);
aRow.remove(col);
aRow.insertElementAt(newVal, col);
fireTableCellUpdated(row, col);
}
public void setColumnVisible(int index, boolean visible) {
_columnsVisible[index] = visible;
fireTableStructureChanged();
}
}
}
Your problem in getColumnClass method as you see you also return Object because of that you also get String columns.
You can determine that method in next way:
#Override
public Class<?> getColumnClass(int arg0) {
return longValues[arg0].getClass();
}
Or return Classes for your columns in another way. But you must to determine this Classes while cunstruct your model.
Hi I am using a JTable to display data from a file. For this I like to have row headers and column headers. Since row headers are not there I implemented a seprate JTable for it.
But now I like to resize row headers and row grids. Is there anyway I can implement such excel like functionality.
I followed row header functionality from the url:-
http://tips4java.wordpress.com/2008/11/18/row-number-table/ and grid resize from the url:- http://www.jroller.com/santhosh/entry/make_jtable_resiable_better_than
Now after integrating both the codes I sucessfully got the row header and draggable grid.
But now after resizing grids I didn't find a way to make row headers draggable.
Please suggest something to make rowheaders draggable.
**SimpleTableDemo.java**
package com.swing.table;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.table.*;
import java.util.*;
import java.awt.*;
public class SimpleTableDemo extends JPanel {
private boolean DEBUG = false;
private int spacing = 6;
private Map columnSizes = new HashMap();
String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years",
"Vegetarian" };
Object[][] data = {
{
"Kathy",
"Smith",
"SnowboardingXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
new Integer(5), new Boolean(false) },
{ "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
{ "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
{ "Jane", "White", "Speed reading", new Integer(20),
new Boolean(true) },
{ "Joe", "Brown", "Pool", new Integer(10), new Boolean(false) } };
final JTable table = new JTable(data, columnNames);
Panel1 panel;
public SimpleTableDemo() {
super(new GridLayout(0, 1));
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
// table.setFillsViewportHeight(true);
if (DEBUG) {
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
printDebugData(table);
}
});
}
// Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
JTable rowTable = new RowNumberTable(table);
scrollPane.setRowHeaderView(rowTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
rowTable.getTableHeader());
// Add the scroll pane to this panel.
add(scrollPane);
/*
* panel = new Panel1(); Rectangle rect = table.getCellRect(0,0,true);
*
* panel.setX(table.getWidth()); panel.setY(0);
* panel.setWidth(rect.width); panel.setHeight(rect.height);
* panel.setStr(table.getModel().getValueAt(0,0).toString());
* panel.setModel(table);
*
* add(panel);
*/
/*
* final JComboBox jNumberComboBoxSize = new JComboBox();
* jNumberComboBoxSize.setModel(new javax.swing.DefaultComboBoxModel(new
* String[] { "11", "12", "14", "16", "18", "20", "24", "30", "36",
* "48", "72" })); jNumberComboBoxSize.addActionListener(new
* java.awt.event.ActionListener() { public void
* actionPerformed(java.awt.event.ActionEvent evt) {
* jNumberComboBoxSizeActionPerformed(jNumberComboBoxSize); } });
*
* JPanel panel2 = new JPanel(); panel2.add(jNumberComboBoxSize);
*
* add(panel2);
*/
TableRowResizer rowResizer = new TableRowResizer(table);
adjustColumns();
}
private void jNumberComboBoxSizeActionPerformed(
JComboBox jNumberComboBoxSize) {
int fontSize = Integer.parseInt(jNumberComboBoxSize.getSelectedItem()
.toString());
table.setRowHeight(fontSize);
table.setFont(new Font("Serif", Font.BOLD, fontSize));
Rectangle rect = table.getCellRect(0, 0, true);
panel.setX(0);
panel.setY(0);
// panel.setWidth(rect.width);
panel.setHeight(rect.height);
panel.setStr(table.getModel().getValueAt(0, 0).toString());
panel.setModel(table);
panel.repaint();
table.revalidate();
}
private void printDebugData(JTable table) {
int numRows = table.getRowCount();
int numCols = table.getColumnCount();
javax.swing.table.TableModel model = table.getModel();
System.out.println("Value of data: ");
for (int i = 0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j = 0; j < numCols; j++) {
System.out.print(" " + model.getValueAt(i, j));
}
System.out.println();
}
System.out.println("--------------------------");
}
/*
* Adjust the widths of all the columns in the table
*/
public void adjustColumns() {
TableColumnModel tcm = table.getColumnModel();
for (int i = 0; i < tcm.getColumnCount(); i++) {
adjustColumn(i);
}
}
/*
* Adjust the width of the specified column in the table
*/
public void adjustColumn(final int column) {
TableColumn tableColumn = table.getColumnModel().getColumn(column);
if (!tableColumn.getResizable())
return;
int columnHeaderWidth = getColumnHeaderWidth(column);
int columnDataWidth = getColumnDataWidth(column);
int preferredWidth = Math.max(columnHeaderWidth, columnDataWidth);
panel.setWidth(preferredWidth);
updateTableColumn(column, preferredWidth);
}
/*
* Calculated the width based on the column name
*/
private int getColumnHeaderWidth(int column) {
TableColumn tableColumn = table.getColumnModel().getColumn(column);
Object value = tableColumn.getHeaderValue();
TableCellRenderer renderer = tableColumn.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component c = renderer.getTableCellRendererComponent(table, value,
false, false, -1, column);
return c.getPreferredSize().width;
}
/*
* Calculate the width based on the widest cell renderer for the given
* column.
*/
private int getColumnDataWidth(int column) {
int preferredWidth = 0;
int maxWidth = table.getColumnModel().getColumn(column).getMaxWidth();
for (int row = 0; row < table.getRowCount(); row++) {
preferredWidth = Math.max(preferredWidth,
getCellDataWidth(row, column));
// We've exceeded the maximum width, no need to check other rows
if (preferredWidth >= maxWidth)
break;
}
return preferredWidth;
}
/*
* Get the preferred width for the specified cell
*/
private int getCellDataWidth(int row, int column) {
// Inovke the renderer for the cell to calculate the preferred width
TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
Component c = table.prepareRenderer(cellRenderer, row, column);
int width = c.getPreferredSize().width
+ table.getIntercellSpacing().width;
return width;
}
/*
* Update the TableColumn with the newly calculated width
*/
private void updateTableColumn(int column, int width) {
final TableColumn tableColumn = table.getColumnModel()
.getColumn(column);
if (!tableColumn.getResizable())
return;
width += spacing;
// Don't shrink the column width
width = Math.max(width, tableColumn.getPreferredWidth());
columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
table.getTableHeader().setResizingColumn(tableColumn);
tableColumn.setWidth(width);
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create and set up the content pane.
SimpleTableDemo newContentPane = new SimpleTableDemo();
newContentPane.setOpaque(true); // content panes must be opaque
frame.setContentPane(newContentPane);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
class Panel1 extends JPanel {
int x;
int y;
int width;
int height;
String str;
JTable model;
public void setModel(JTable model) {
this.model = model;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setWidth(int w) {
this.width = w;
}
public void setHeight(int h) {
this.height = h;
}
public void setStr(String s) {
this.str = s;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int initX = 0;
for (int row = 0; row < 5; ++row) {
initX = x;
for (int col = 0; col < 5; ++col) {
g.drawRect(x, y, width, height);
g.drawString(model.getModel().getValueAt(row, col).toString(),
x + 10, y + 10);
x = x + width;
}
x = initX;
y = y + height;
}
}
};
**TableRowResizer.java**
package com.swing.table;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.JTable;
import javax.swing.event.MouseInputAdapter;
// #author Santhosh Kumar T - santhosh#in.fiorano.com
public class TableRowResizer extends MouseInputAdapter {
public static Cursor resizeCursor = Cursor
.getPredefinedCursor(Cursor.N_RESIZE_CURSOR);
private int mouseYOffset, resizingRow;
private Cursor otherCursor = resizeCursor;
private JTable table;
public TableRowResizer(JTable table) {
this.table = table;
table.addMouseListener(this);
table.addMouseMotionListener(this);
}
private int getResizingRow(Point p) {
return getResizingRow(p, table.rowAtPoint(p));
}
private int getResizingRow(Point p, int row) {
if (row == -1) {
return -1;
}
int col = table.columnAtPoint(p);
if (col == -1)
return -1;
Rectangle r = table.getCellRect(row, col, true);
r.grow(0, -3);
if (r.contains(p))
return -1;
int midPoint = r.y + r.height / 2;
int rowIndex = (p.y < midPoint) ? row - 1 : row;
return rowIndex;
}
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
resizingRow = getResizingRow(p);
mouseYOffset = p.y - table.getRowHeight(resizingRow);
}
private void swapCursor() {
Cursor tmp = table.getCursor();
table.setCursor(otherCursor);
otherCursor = tmp;
}
public void mouseMoved(MouseEvent e) {
if ((getResizingRow(e.getPoint()) >= 0) != (table.getCursor() == resizeCursor)) {
swapCursor();
}
}
public void mouseDragged(MouseEvent e) {
int mouseY = e.getY();
if (resizingRow >= 0) {
int newHeight = mouseY - mouseYOffset;
if (newHeight > 0)
table.setRowHeight(resizingRow, newHeight);
}
}
}
**RowNumberTable.java**
package com.swing.table;
import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
/*
* Use a JTable as a renderer for row numbers of a given main table.
* This table must be added to the row header of the scrollpane that
* contains the main table.
*/
public class RowNumberTable extends JTable implements ChangeListener,
PropertyChangeListener {
private final JTable table;
public RowNumberTable(JTable table) {
this.table = table;
table.addPropertyChangeListener(this);
setFocusable(false);
setAutoCreateColumnsFromModel(false);
updateRowHeight();
updateModel();
updateSelectionModel();
TableColumn column = new TableColumn();
column.setHeaderValue("");
addColumn(column);
column.setCellRenderer(new RowNumberRenderer());
getColumnModel().getColumn(0).setPreferredWidth(50);
setPreferredScrollableViewportSize(getPreferredSize());
getTableHeader().setReorderingAllowed(false);
}
#Override
public void addNotify() {
super.addNotify();
Component c = getParent();
// Keep scrolling of the row table in sync with the main table.
if (c instanceof JViewport) {
JViewport viewport = (JViewport) c;
viewport.addChangeListener(this);
}
}
/*
* Delegate method to main table
*/
#Override
public int getRowCount() {
return table.getRowCount();
}
#Override
public int getRowHeight(int row) {
return table.getRowHeight(row);
}
/*
* This table does not use any data from the main TableModel, so just return
* a value based on the row parameter.
*/
#Override
public Object getValueAt(int row, int column) {
return Integer.toString(row + 1);
}
/*
* Don't edit data in the main TableModel by mistake
*/
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
// implements ChangeListener
public void stateChanged(ChangeEvent e) {
// Keep the scrolling of the row table in sync with main table
JViewport viewport = (JViewport) e.getSource();
JScrollPane scrollPane = (JScrollPane) viewport.getParent();
scrollPane.getVerticalScrollBar()
.setValue(viewport.getViewPosition().y);
}
// implements PropertyChangeListener
public void propertyChange(PropertyChangeEvent e) {
// Keep the row table in sync with the main table
if ("rowHeight".equals(e.getPropertyName())) {
updateRowHeight();
}
if ("selectionModel".equals(e.getPropertyName())) {
updateSelectionModel();
}
if ("model".equals(e.getPropertyName())) {
updateModel();
}
}
private void updateRowHeight() {
setRowHeight(table.getRowHeight());
}
private void updateModel() {
setModel(table.getModel());
}
private void updateSelectionModel() {
setSelectionModel(table.getSelectionModel());
}
/*
* Borrow the renderer from JDK1.4.2 table header
*/
private static class RowNumberRenderer extends DefaultTableCellRenderer {
public RowNumberRenderer() {
setHorizontalAlignment(JLabel.CENTER);
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
if (table != null) {
JTableHeader header = table.getTableHeader();
if (header != null) {
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
}
if (isSelected) {
setFont(getFont().deriveFont(Font.BOLD));
}
setText((value == null) ? "" : value.toString());
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
}
}
I'm using answer https://stackoverflow.com/a/5820366 and http://tips4java.wordpress.com/2008/11/10/table-column-adjuster/ and it works, but frequently columns' sizes are too wide or too narrow.
No matter filling my table with HTML or text.
Using standard TableModel from oracle documentation.
Resize mode = JTable.AUTO_RESIZE_OFF
Container of my tabel is jGoodies:
FormLayout currentEventLayout = new FormLayout(
"fill:p",
"pref, pref");
PanelBuilder currentEventBuilder = new PanelBuilder(currentEventLayout);
currentEventBuilder.add(mainQuotesTable.getTableHeader(), constraints.xy(1, 1));
currentEventBuilder.add(mainQuotesTable, constraints.xy(1, 2));
HTML example:
"<html><pre><font size=+1 face='Arial'>" + firstValue + "\n" + secondValue + "</font></pre></html>"
simple row:
firstValue + " - " + secondValue
Here is the example:
public class TableAdjustExample {
private static JTable mainTable;
private static Random random = new Random();
private static List<Data> data;
private static class Data {
String name;
String surname;
private Data(String name, String surname) {
this.name = name;
this.surname = surname;
}
}
public static void main(String[] args) {
data = stubProvider();
final JFrame frame = new JFrame("table adjust example");
frame.add(createUI());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(350, 400);
frame.setVisible(true);
update();
java.util.Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
update();
}
}, 3000, 3000);
}
private static JPanel createUI() {
JPanel jPanel = new JPanel();
mainTable = new JTable(2, 3);
mainTable.setModel(new AbstractTableModel() {
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Data dataItem = data.get(rowIndex);
if (columnIndex == 0) {
return dataItem.name;
}
if (columnIndex == 1) {
return dataItem.surname;
}
throw new IllegalStateException();
}
});
mainTable.setGridColor(Color.black);
mainTable.setShowHorizontalLines(false);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
final TableCellRenderer defaultRenderer = mainTable.getTableHeader().getDefaultRenderer();
mainTable.getTableHeader().setDefaultRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable jTable, Object o, boolean b, boolean b1, int row, int column) {
JLabel parent = (JLabel) defaultRenderer.getTableCellRendererComponent(jTable, o, b, b1, row, column);
if (column == 0) {
parent.setText("name");
} else {
parent.setText("surname");
}
return parent;
}
});
jPanel.add(mainTable.getTableHeader());
jPanel.add(mainTable);
return jPanel;
}
private static void update() {
System.out.println("updating");
data = stubProvider();
adjustJTableRowSizes(mainTable);
for (int i = 0; i < mainTable.getColumnCount(); i++) {
adjustColumnSizes(mainTable, i, 2);
}
}
private static void adjustJTableRowSizes(JTable jTable) {
for (int row = 0; row < jTable.getRowCount(); row++) {
int maxHeight = 0;
for (int column = 0; column < jTable.getColumnCount(); column++) {
TableCellRenderer cellRenderer = jTable.getCellRenderer(row, column);
Object valueAt = jTable.getValueAt(row, column);
Component tableCellRendererComponent = cellRenderer.getTableCellRendererComponent(jTable, valueAt, false, false, row, column);
int heightPreferable = tableCellRendererComponent.getPreferredSize().height;
maxHeight = Math.max(heightPreferable, maxHeight);
}
jTable.setRowHeight(row, maxHeight);
}
}
public static void adjustColumnSizes(JTable table, int column, int margin) {
DefaultTableColumnModel colModel = (DefaultTableColumnModel) table.getColumnModel();
TableColumn col = colModel.getColumn(column);
int width;
TableCellRenderer renderer = col.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
JLabel comp = (JLabel) renderer.getTableCellRendererComponent(
table, col.getHeaderValue(), false, false, 0, 0);
width = comp.getPreferredSize().width;
for (int r = 0; r < table.getRowCount(); r++) {
renderer = table.getCellRenderer(r, column);
comp = (JLabel) renderer.getTableCellRendererComponent(
table, table.getValueAt(r, column), false, false, r, column);
int currentWidth = comp.getPreferredSize().width;
width = Math.max(width, currentWidth);
}
width += 2 * margin;
col.setPreferredWidth(width);
}
private static List<Data> stubProvider() {
List<Data> data = new ArrayList<Data>();
for (int i = 0; i < 4; i++) {
data.add(new Data(
"<html>" +
"<div style='font-size: 15px'>Jason</div>" +
"<div style='font-size: 15px'>" + random.nextInt() + "</div>" +
"</html>",
"Statham " + random.nextInt()));
}
return data;
}
}
I have such problem with row height adjustment. Using of <pre>\n</pre> instead of <br> fixed row adjustment.
Seems to be working okay for me...
public class TestTable01 extends JPanel {
private JTable mainTable;
public TestTable01() {
super(new GridLayout(1, 0));
String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
Object[][] data = {
{"Kathy", "Smith",
"Snowboarding", new Integer(5), new Boolean(false)},
{"John", "Doe",
"Rowing", new Integer(3), new Boolean(true)},
{"Sue", "Black",
"Knitting", new Integer(2), new Boolean(false)},
{"Jane", "White",
"Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown",
"Pool", new Integer(10), new Boolean(false)}
};
mainTable = new JTable(data, columnNames);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
mainTable.setPreferredScrollableViewportSize(new Dimension(500, 70));
mainTable.setFillsViewportHeight(true);
update();
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(mainTable);
//Add the scroll pane to this panel.
add(scrollPane);
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
TestTable01 newContentPane = new TestTable01();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
private void update() {
System.out.println("updating");
adjustJTableRowSizes(mainTable);
for (int i = 0; i < mainTable.getColumnCount(); i++) {
adjustColumnSizes(mainTable, i, 2);
}
}
private void adjustJTableRowSizes(JTable jTable) {
for (int row = 0; row < jTable.getRowCount(); row++) {
int maxHeight = 0;
for (int column = 0; column < jTable.getColumnCount(); column++) {
TableCellRenderer cellRenderer = jTable.getCellRenderer(row, column);
Object valueAt = jTable.getValueAt(row, column);
Component tableCellRendererComponent = cellRenderer.getTableCellRendererComponent(jTable, valueAt, false, false, row, column);
int heightPreferable = tableCellRendererComponent.getPreferredSize().height;
maxHeight = Math.max(heightPreferable, maxHeight);
}
jTable.setRowHeight(row, maxHeight);
}
}
public void adjustColumnSizes(JTable table, int column, int margin) {
DefaultTableColumnModel colModel = (DefaultTableColumnModel) table.getColumnModel();
TableColumn col = colModel.getColumn(column);
int width;
TableCellRenderer renderer = col.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(table, col.getHeaderValue(), false, false, 0, 0);
width = comp.getPreferredSize().width;
for (int r = 0; r < table.getRowCount(); r++) {
renderer = table.getCellRenderer(r, column);
comp = renderer.getTableCellRendererComponent(table, table.getValueAt(r, column), false, false, r, column);
int currentWidth = comp.getPreferredSize().width;
width = Math.max(width, currentWidth);
}
width += 2 * margin;
col.setPreferredWidth(width);
col.setWidth(width);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
UPDATED
There are a number of issues with your example.
Tables really should be added to a JScrollPane, this will take care of adding the header...
The default layout manager for a JPanel is FlowLayout, in this case, it's probably not what you want, you probably want to use a BorderLayout
Swing is not thread safe. The user of java.util.Timer will violate this policy, this could cause the model and view to fall out sync. Use a javax.swing.Timer instead.
Rendering two <div> next to each will cause the html layout engine to place a weak break between the elements. That is, if the engine decides there's not enough available space to render the two elements together, it will split them. Better to use a single <div> with two <span> tags instead...
I would have a read of
Concurrency in Swing
How to Use Tables
public class TestColumnWidths {
private static JTable mainTable;
private static Random random = new Random();
private static List<Data> data;
private static class Data {
String name;
String surname;
private Data(String name, String surname) {
this.name = name;
this.surname = surname;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
data = stubProvider();
final JFrame frame = new JFrame("table adjust example");
frame.add(createUI());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
update();
// java.util.Timer timer = new java.util.Timer();
// timer.schedule(new TimerTask() {
// #Override
// public void run() {
// update();
// }
// }, 3000, 3000);
javax.swing.Timer timer = new javax.swing.Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
private static JPanel createUI() {
JPanel jPanel = new JPanel();
mainTable = new JTable(2, 3);
mainTable.setModel(new AbstractTableModel() {
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Data dataItem = data.get(rowIndex);
if (columnIndex == 0) {
return dataItem.name;
}
if (columnIndex == 1) {
return dataItem.surname;
}
throw new IllegalStateException();
}
});
mainTable.setGridColor(Color.black);
mainTable.setShowHorizontalLines(false);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
final TableCellRenderer defaultRenderer = mainTable.getTableHeader().getDefaultRenderer();
mainTable.getTableHeader().setDefaultRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable jTable, Object o, boolean b, boolean b1, int row, int column) {
JLabel parent = (JLabel) defaultRenderer.getTableCellRendererComponent(jTable, o, b, b1, row, column);
if (column == 0) {
parent.setText("name");
} else {
parent.setText("surname");
}
return parent;
}
});
// jPanel.add(mainTable.getTableHeader());
// jPanel.add(mainTable);
jPanel.setLayout(new BorderLayout());
jPanel.add(new JScrollPane(mainTable));
return jPanel;
}
private static void update() {
System.out.println("updating");
data = stubProvider();
adjustJTableRowSizes(mainTable);
for (int i = 0; i < mainTable.getColumnCount(); i++) {
adjustColumnSizes(mainTable, i, 2);
}
}
private static void adjustJTableRowSizes(JTable jTable) {
for (int row = 0; row < jTable.getRowCount(); row++) {
int maxHeight = 0;
for (int column = 0; column < jTable.getColumnCount(); column++) {
TableCellRenderer cellRenderer = jTable.getCellRenderer(row, column);
Object valueAt = jTable.getValueAt(row, column);
Component tableCellRendererComponent = cellRenderer.getTableCellRendererComponent(jTable, valueAt, false, false, row, column);
int heightPreferable = tableCellRendererComponent.getPreferredSize().height;
maxHeight = Math.max(heightPreferable, maxHeight);
}
jTable.setRowHeight(row, maxHeight);
}
}
public static void adjustColumnSizes(JTable table, int column, int margin) {
DefaultTableColumnModel colModel = (DefaultTableColumnModel) table.getColumnModel();
TableColumn col = colModel.getColumn(column);
int width;
TableCellRenderer renderer = col.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(
table, col.getHeaderValue(), false, false, 0, 0);
width = comp.getPreferredSize().width;
for (int r = 0; r < table.getRowCount(); r++) {
renderer = table.getCellRenderer(r, column);
comp = renderer.getTableCellRendererComponent(
table, table.getValueAt(r, column), false, false, r, column);
int currentWidth = comp.getPreferredSize().width;
width = Math.max(width, currentWidth);
}
width += 2 * margin;
col.setPreferredWidth(width);
}
private static List<Data> stubProvider() {
List<Data> data = new ArrayList<Data>();
for (int i = 0; i < 4; i++) {
data.add(new Data(
"<html>"
+ "<div>"
+ "<span style='font-size: 15px'>Jason</span>"
+ "<span style='font-size: 15px'>" + random.nextInt() + "</span>"
+ "</div>"
+ "</html>",
"Statham " + random.nextInt()));
}
return data;
}
}
Set reasonable MinimumWidth for the columns which are too narrow. Then calculate width according to the contents of the columns and set them.