Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ezhov-da/81eab375c9999e302c1f07bf5d366125 to your computer and use it in GitHub Desktop.
Save ezhov-da/81eab375c9999e302c1f07bf5d366125 to your computer and use it in GitHub Desktop.
java автоматическая ширина столбцов jtable
/*
Данный класс позволяет динамически менять ширину столбцов таблицы и сам отслеживает это.
Для первоначальныйх настроек необходимо:
1. Передать в конструктор таблицу
2. Поставить для таблицы: таблица.setAutoResizeMode(JXTreeTable.AUTO_RESIZE_ALL_COLUMNS);
3. Вызвать у класса метод: setDynamicAdjustment(true);
https://tips4java.wordpress.com/2008/11/10/table-column-adjuster/
Table Column Adjuster
Posted by Rob Camick on November 10, 2008
JTable sets a default width for each TableColumn in the table. When designing the table you can alter this width by setting the preferred size of the table column. However this size is only going to be a best guess as to the real width of the column. The real width of the column will never be known until data has been loaded in the table. It would be nice to be able to alter the width of the columns so that all text in the cell is displayed.
The most accurate solution is to use the actual TableCellRenderer of each column in the JTable to calculate the preferred width of the cell based on the data contained in each cell. A basic implementation of this approach could be:
*/
JTable table = new JTable( ... );
table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
for (int column = 0; column < table.getColumnCount(); column++)
{
TableColumn tableColumn = table.getColumnModel().getColumn(column);
int preferredWidth = tableColumn.getMinWidth();
int maxWidth = tableColumn.getMaxWidth();
for (int row = 0; row < table.getRowCount(); row++)
{
TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
Component c = table.prepareRenderer(cellRenderer, row, column);
int width = c.getPreferredSize().width + table.getIntercellSpacing().width;
preferredWidth = Math.max(preferredWidth, width);
// We've exceeded the maximum width, no need to check other rows
if (preferredWidth >= maxWidth)
{
preferredWidth = maxWidth;
break;
}
}
tableColumn.setPreferredWidth( preferredWidth );
}
This simple implementation will only work for static data and does not include the column header when determining the width of the column. For more features you may want to consider using the TableColumnAdjuster described below. It provides more dynamic features for handling changes to the data in the TableModel.
In many cases a JTable will contain dynamic data. Maybe rows of data can be added or removed from the table, or maybe the user has the ability to modify the data in the cell of a table. Either of these changes may result in the preferred width of a column changing. In these cases you may want the ability to change the column widths after data is initially loaded and the ability to alter columns widths as the user changes the data in the table. The TableColumnAdjuster can handle these situations. That is not only can the TableColumnAdjuster be used to determine the initial columns widths, it can be configured to support dynamic calculation of column widths as the data changes.
To help the TableColumnAdjuster calculate the appropriate column width you can set the following properties:
Column Header Included – use the width of the column header
Column Data Included – loop through all the rows of the TableModel and find the cell renderer with the largest width
Only Adjust Larger – only reset the column width if the calculated value is greater than the current width of the column.
The maximum width calculated using the above properties will be used for the column width. To provide default column widths you might use code like the following which will generate the table shown in the image:
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumnAdjuster tca = new TableColumnAdjuster(table);
tca.adjustColumns();
Above is an example of installing the column adjuster and using static adjustments. As mentioned earlier the TableColumnAdjuster also supports dynamic column adjusts using the following property:
Dynamic Adjustment – changes to the TableModel will cause the adjustments to occur automatically. Updating a table cell will cause the column to be adjusted. Adding/removing rows will cause all columns to be adjusted.
The user may find the dynamic adjustment a bit annoying if the width changes every time they type something, so we can also give the user to option to request column adjustments. This was done by adding Actions to the table which the user can invoke with the appropriate key stroke:
Action Key Stroke
Adjust Column Control +
Adjust Columns Control Shift +
Restore Column Control –
Restore Columns Control Shift –
Toggle Dynamic Control *
Toggle Larger Control /
There are four main methods that can be used to change the column widths:
Adjust Column – adjust the width of the specified column
Adjust Columns – adjust the width of all columns
Restore Column – restore the width of the specified column
Restore Columns – restore the width of all columns
Typically, you would only use the “Adjust Columns” method to initially set up the widths for all columns. The other methods are used to support the keyboard functionality.
Note, that this class was designed to be used with tables that use an auto resize mode of AUTO_RESIZE_OFF. With all other modes you are constrained, as the width of the columns must fit inside the table. So if you increase the width of one column, the widths of one or more of the other columns must decrease. Because of this, the resize mode of RESIZE_ALL_COLUMNS will work the best.
Hopefully the usage of the static methods along with the user controlled Actions will provide the flexibility needed to adjust the width of any column in any situation.
//КЛАСС ДЛЯ РАБОТЫ
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
/*
* Class to manage the widths of colunmns in a table.
*
* Various properties control how the width of the column is calculated.
* Another property controls whether column width calculation should be dynamic.
* Finally, various Actions will be added to the table to allow the user
* to customize the functionality.
*
* This class was designed to be used with tables that use an auto resize mode
* of AUTO_RESIZE_OFF. With all other modes you are constrained as the width
* of the columns must fit inside the table. So if you increase one column, one
* or more of the other columns must decrease. Because of this the resize mode
* of RESIZE_ALL_COLUMNS will work the best.
*/
public class TableColumnAdjuster implements PropertyChangeListener, TableModelListener
{
private JTable table;
private int spacing;
private boolean isColumnHeaderIncluded;
private boolean isColumnDataIncluded;
private boolean isOnlyAdjustLarger;
private boolean isDynamicAdjustment;
private Map<TableColumn, Integer> columnSizes = new HashMap<TableColumn, Integer>();
/*
* Specify the table and use default spacing
*/
public TableColumnAdjuster(JTable table)
{
this(table, 6);
}
/*
* Specify the table and spacing
*/
public TableColumnAdjuster(JTable table, int spacing)
{
this.table = table;
this.spacing = spacing;
setColumnHeaderIncluded(true);
setColumnDataIncluded(true);
setOnlyAdjustLarger(false);
setDynamicAdjustment(false);
installActions();
}
/*
* 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);
updateTableColumn(column, preferredWidth);
}
/*
* Calculated the width based on the column name
*/
private int getColumnHeaderWidth(int column)
{
if (!isColumnHeaderIncluded)
{
return 0;
}
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)
{
if (!isColumnDataIncluded)
{
return 0;
}
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
if (isOnlyAdjustLarger)
{
width = Math.max(width, tableColumn.getPreferredWidth());
}
columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
table.getTableHeader().setResizingColumn(tableColumn);
tableColumn.setWidth(width);
}
/*
* Restore the widths of the columns in the table to its previous width
*/
public void restoreColumns()
{
TableColumnModel tcm = table.getColumnModel();
for (int i = 0; i < tcm.getColumnCount(); i++)
{
restoreColumn(i);
}
}
/*
* Restore the width of the specified column to its previous width
*/
private void restoreColumn(int column)
{
TableColumn tableColumn = table.getColumnModel().getColumn(column);
Integer width = columnSizes.get(tableColumn);
if (width != null)
{
table.getTableHeader().setResizingColumn(tableColumn);
tableColumn.setWidth(width.intValue());
}
}
/*
* Indicates whether to include the header in the width calculation
*/
public void setColumnHeaderIncluded(boolean isColumnHeaderIncluded)
{
this.isColumnHeaderIncluded = isColumnHeaderIncluded;
}
/*
* Indicates whether to include the model data in the width calculation
*/
public void setColumnDataIncluded(boolean isColumnDataIncluded)
{
this.isColumnDataIncluded = isColumnDataIncluded;
}
/*
* Indicates whether columns can only be increased in size
*/
public void setOnlyAdjustLarger(boolean isOnlyAdjustLarger)
{
this.isOnlyAdjustLarger = isOnlyAdjustLarger;
}
/*
* Indicate whether changes to the model should cause the width to be
* dynamically recalculated.
*/
public void setDynamicAdjustment(boolean isDynamicAdjustment)
{
// May need to add or remove the TableModelListener when changed
if (this.isDynamicAdjustment != isDynamicAdjustment)
{
if (isDynamicAdjustment)
{
table.addPropertyChangeListener(this);
table.getModel().addTableModelListener(this);
} else
{
table.removePropertyChangeListener(this);
table.getModel().removeTableModelListener(this);
}
}
this.isDynamicAdjustment = isDynamicAdjustment;
}
//
// Implement the PropertyChangeListener
//
public void propertyChange(PropertyChangeEvent e)
{
// When the TableModel changes we need to update the listeners
// and column widths
if ("model".equals(e.getPropertyName()))
{
TableModel model = (TableModel) e.getOldValue();
model.removeTableModelListener(this);
model = (TableModel) e.getNewValue();
model.addTableModelListener(this);
adjustColumns();
}
}
//
// Implement the TableModelListener
//
public void tableChanged(final TableModelEvent e)
{
if (!isColumnDataIncluded)
{
return;
}
// Needed when table is sorted.
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// A cell has been updated
int column = table.convertColumnIndexToView(e.getColumn());
if (e.getType() == TableModelEvent.UPDATE && column != -1)
{
// Only need to worry about an increase in width for this cell
if (isOnlyAdjustLarger)
{
int row = e.getFirstRow();
TableColumn tableColumn = table.getColumnModel().getColumn(column);
if (tableColumn.getResizable())
{
int width = getCellDataWidth(row, column);
updateTableColumn(column, width);
}
} // Could be an increase of decrease so check all rows
else
{
adjustColumn(column);
}
} // The update affected more than one column so adjust all columns
else
{
adjustColumns();
}
}
});
}
/*
* Install Actions to give user control of certain functionality.
*/
private void installActions()
{
installColumnAction(true, true, "adjustColumn", "control ADD");
installColumnAction(false, true, "adjustColumns", "control shift ADD");
installColumnAction(true, false, "restoreColumn", "control SUBTRACT");
installColumnAction(false, false, "restoreColumns", "control shift SUBTRACT");
installToggleAction(true, false, "toggleDynamic", "control MULTIPLY");
installToggleAction(false, true, "toggleLarger", "control DIVIDE");
}
/*
* Update the input and action maps with a new ColumnAction
*/
private void installColumnAction(
boolean isSelectedColumn, boolean isAdjust, String key, String keyStroke)
{
Action action = new ColumnAction(isSelectedColumn, isAdjust);
KeyStroke ks = KeyStroke.getKeyStroke(keyStroke);
table.getInputMap().put(ks, key);
table.getActionMap().put(key, action);
}
/*
* Update the input and action maps with new ToggleAction
*/
private void installToggleAction(
boolean isToggleDynamic, boolean isToggleLarger, String key, String keyStroke)
{
Action action = new ToggleAction(isToggleDynamic, isToggleLarger);
KeyStroke ks = KeyStroke.getKeyStroke(keyStroke);
table.getInputMap().put(ks, key);
table.getActionMap().put(key, action);
}
/*
* Action to adjust or restore the width of a single column or all columns
*/
class ColumnAction extends AbstractAction
{
private boolean isSelectedColumn;
private boolean isAdjust;
public ColumnAction(boolean isSelectedColumn, boolean isAdjust)
{
this.isSelectedColumn = isSelectedColumn;
this.isAdjust = isAdjust;
}
@Override
public void actionPerformed(ActionEvent e)
{
// Handle selected column(s) width change actions
if (isSelectedColumn)
{
int[] columns = table.getSelectedColumns();
for (int i = 0; i < columns.length; i++)
{
if (isAdjust)
{
adjustColumn(columns[i]);
} else
{
restoreColumn(columns[i]);
}
}
} else
{
if (isAdjust)
{
adjustColumns();
} else
{
restoreColumns();
}
}
}
}
/*
* Toggle properties of the TableColumnAdjuster so the user can
* customize the functionality to their preferences
*/
class ToggleAction extends AbstractAction
{
private boolean isToggleDynamic;
private boolean isToggleLarger;
public ToggleAction(boolean isToggleDynamic, boolean isToggleLarger)
{
this.isToggleDynamic = isToggleDynamic;
this.isToggleLarger = isToggleLarger;
}
@Override
public void actionPerformed(ActionEvent e)
{
if (isToggleDynamic)
{
setDynamicAdjustment(!isDynamicAdjustment);
return;
}
if (isToggleLarger)
{
setOnlyAdjustLarger(!isOnlyAdjustLarger);
return;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment