Actually JTextArea already implements all the features required to dynamically change its height based on its width. One can see this functionality in action, when JTextArea is used inside a ScrollPane, where its height is automatically adjusted to fit the width of the ScrollPane. To use this feature, one has to first set the size of the JTextArea to some width and then JTextArea#getPreferredSize() will return the required height to display the text (if line wrap is set to true).
So to dynamically change the row height of a JTable based on its width, one can do the following:
- Add a custom TableCellRenderer to the table that returns a JTextArea in TableCellRenderer#getTableCellRendererComponent()
- Listen to the resizing of the columns as explained here: Java JTable detect Column re-sized by user
- Update the row heights of the columns as explained here: Auto adjust the height of rows in a JTable
- During the update of the row heights, one calculates the required size of the JTextArea by first setting the new width and then getting the preferred height as shown in the following code snippet
Update function of the row heights:
public static void updateRowHeights(int column, int width, JTable table){
for (int row = 0; row < table.getRowCount(); row++) {
int rowHeight = table.getRowHeight();
Component comp = table.prepareRenderer(table.getCellRenderer(row, column), row, column);
Dimension d = comp.getPreferredSize();
// first set the size to the new width
comp.setSize(new Dimension(width, d.height));
// then get the preferred size
d = comp.getPreferredSize();
rowHeight = Math.max(rowHeight, d.height);
// finally set the height of the table
table.setRowHeight(row, rowHeight);
}
}
With this approach, no further calculations of colums or rows are necessary.
Here is the complete code of the OP's ExampleTable, adjusted to this implementation.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class ExampleTable {
public class RowHeightCellRenderer extends JTextArea implements TableCellRenderer {
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
setEditable(false);
setLineWrap(true);
setWrapStyleWord(true);
if (isSelected) {
setBackground(table.getSelectionBackground());
setForeground(table.getSelectionForeground());
} else {
setBackground(table.getBackground());
setForeground(table.getForeground());
}
setText(value.toString());
return this;
}
}
public static void updateRowHeights(int column, int width, JTable table){
for (int row = 0; row < table.getRowCount(); row++) {
int rowHeight = table.getRowHeight();
Component comp = table.prepareRenderer(table.getCellRenderer(row, column), row, column);
Dimension d = comp.getPreferredSize();
comp.setSize(new Dimension(width, d.height));
d = comp.getPreferredSize();
rowHeight = Math.max(rowHeight, d.height);
table.setRowHeight(row, rowHeight);
}
}
public JPanel createTable() {
JPanel totalGUI = new JPanel();
//define titles for table
final String[] columnNames = {"TITLE1", "TITLE2", "TITLE3"};
//table data
final Object[][] rowData = {
{new Integer(34), "Steve", "test test test"},
{new Integer(32), "Patrick", "dumdi dumdi dummdi dumm di di didumm"},
{new Integer(10), "Sarah", "blabla bla bla blabla bla bla blabla"},};
AbstractTableModel model = new AbstractTableModel() {
@Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public String getColumnName(int column) { return columnNames[column].toString(); }
public int getRowCount() { return rowData.length; }
public int getColumnCount() { return columnNames.length; }
public Object getValueAt(int row, int col) { return rowData[row][col]; }
public boolean isCellEditable(int row, int column) { return true; }
public void setValueAt(Object value, int row, int col) {
rowData[row][col] = value;
fireTableCellUpdated(row, col);
}
};
//create object 'textTable'
final JTable textTable = new JTable();
textTable.setDefaultRenderer(String.class, new RowHeightCellRenderer());
textTable.setModel(model);
//set column width
textTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
textTable.getColumnModel().getColumn(0).setPreferredWidth(60);
textTable.getColumnModel().getColumn(1).setPreferredWidth(60);
ColumnListener cl = new ColumnListener(){
@Override
public void columnMoved(int oldLocation, int newLocation) {
}
@Override
public void columnResized(int column, int newWidth) {
updateRowHeights(column, newWidth, textTable);
}
};
textTable.getColumnModel().addColumnModelListener(cl);
textTable.getTableHeader().addMouseListener(cl);
// initial update of row heights
TableColumn c = textTable.getColumnModel().getColumn(2);
updateRowHeights(2, c.getWidth(), textTable);
//scrollbar
JScrollPane scrollPane = new JScrollPane(textTable);
totalGUI.add(scrollPane);
return totalGUI;
}
private static void createAndShowGUI() {
//create main frame
JFrame mainFrame = new JFrame("");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ExampleTable test = new ExampleTable();
JPanel totalGUI = new JPanel();
totalGUI = test.createTable();
//visible mode
mainFrame.add(totalGUI); //integrate main panel to main frame
mainFrame.pack();
mainFrame.setVisible(true);
}
public static void main (String[] args) {
createAndShowGUI();
}//main
abstract class ColumnListener extends MouseAdapter implements TableColumnModelListener {
private int oldIndex = -1;
private int newIndex = -1;
private boolean dragging = false;
private boolean resizing = false;
private int resizingColumn = -1;
private int oldWidth = -1;
@Override
public void mousePressed(MouseEvent e) {
// capture start of resize
if(e.getSource() instanceof JTableHeader) {
JTableHeader header = (JTableHeader)e.getSource();
TableColumn tc = header.getResizingColumn();
if(tc != null) {
resizing = true;
JTable table = header.getTable();
resizingColumn = table.convertColumnIndexToView( tc.getModelIndex());
oldWidth = tc.getPreferredWidth();
} else {
resizingColumn = -1;
oldWidth = -1;
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
// column moved
if(dragging && oldIndex != newIndex) {
columnMoved(oldIndex, newIndex);
}
dragging = false;
oldIndex = -1;
newIndex = -1;
// column resized
if(resizing) {
if(e.getSource() instanceof JTableHeader) {
JTableHeader header = (JTableHeader)e.getSource();
TableColumn tc = header.getColumnModel().getColumn(resizingColumn);
if(tc != null) {
int newWidth = tc.getPreferredWidth();
if(newWidth != oldWidth) {
columnResized(resizingColumn, newWidth);
}
}
}
}
resizing = false;
resizingColumn = -1;
oldWidth = -1;
}
@Override
public void columnAdded(TableColumnModelEvent e) {
}
@Override
public void columnRemoved(TableColumnModelEvent e) {
}
@Override
public void columnMoved(TableColumnModelEvent e) {
// capture dragging
dragging = true;
if(oldIndex == -1){
oldIndex = e.getFromIndex();
}
newIndex = e.getToIndex();
}
@Override
public void columnMarginChanged(ChangeEvent e) {
}
@Override
public void columnSelectionChanged(ListSelectionEvent e) {
}
public abstract void columnMoved(int oldLocation, int newLocation);
public abstract void columnResized(int column, int newWidth);
}
}
Note, that I reused and changed some of the code from Java JTable detect Column re-sized by user and Auto adjust the height of rows in a JTable.