8387267: Editor for the last column in JTable is hard to activate after AUTO_RESIZE_LAST_COLUMN was configured

8388467: Test "api/javax_swing/interactive/JTableTests.html" JTable freezes during rapid column resize

Reviewed-by: angorya, kizune, jdv
This commit is contained in:
Prasanta Sadhukhan
2026-08-15 08:16:46 +00:00
parent 2749a4c0b4
commit 3d47518697
2 changed files with 142 additions and 20 deletions
@@ -453,6 +453,14 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
* needed.
*/
private boolean columnSelectionAdjusting;
/*
* True after column widths have been initialized/synchronized by layout.
* Used to distinguish the first preferred-width layout from later normal
* AUTO_RESIZE_LAST_COLUMN layouts.
*/
private boolean columnWidthsInitialized;
/**
* The last value of getValueIsAdjusting from the row selection models
* valueChanged notification. Used to test if a repaint is needed.
@@ -1264,12 +1272,6 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
autoResizeMode = mode;
resizeAndRepaint();
if (tableHeader != null) {
if (mode == JTable.AUTO_RESIZE_LAST_COLUMN) {
int colCnt = columnModel.getColumnCount();
if (colCnt > 0) {
tableHeader.setResizingColumn(columnModel.getColumn(colCnt - 1));
}
}
tableHeader.resizeAndRepaint();
}
firePropertyChange("autoResizeMode", old, autoResizeMode);
@@ -3193,21 +3195,8 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
*/
public void doLayout() {
boolean prefWidthSet = false;
TableColumn resizingColumn = getResizingColumn();
// doLayout is called for both pack and show
// so if initial preferred width is set by user then
// it needs to be honoured even if resizingColumn
// is set to last column on account of
// AUTO_RESIZE_LAST_COLUMN autoResizeMode
for (int i = 0; i < columnModel.getColumnCount(); i++) {
if (columnModel.getColumn(i).getPreferredWidth() != 75
&& columnModel.getColumn(i).getWidth() == 75) {
prefWidthSet = true;
break;
}
}
if (resizingColumn == null || prefWidthSet) {
if (resizingColumn == null) {
setWidthsFromPreferredWidths(false);
}
else {
@@ -3294,7 +3283,42 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
}
}
private void accommodateLastColumnOnly() {
int columnCount = getColumnCount();
if (columnCount == 0) {
return;
}
int delta = getWidth() - getColumnModel().getTotalColumnWidth();
if (delta != 0) {
accommodateDelta(columnCount - 1, delta);
}
}
private void setWidthsFromPreferredWidthsLastColumnOnly() {
int columnCount = getColumnCount();
if (columnCount == 0) {
return;
}
for (int i = 0; i < columnCount - 1; i++) {
TableColumn column = columnModel.getColumn(i);
column.setWidth(column.getPreferredWidth());
}
accommodateLastColumnOnly();
}
private void setWidthsFromPreferredWidths(final boolean inverse) {
if (!inverse && autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
if (!columnWidthsInitialized) {
setWidthsFromPreferredWidthsLastColumnOnly();
} else {
accommodateLastColumnOnly();
}
columnWidthsInitialized = true;
return;
}
int totalWidth = getWidth();
int totalPreferred = getPreferredSize().width;
int target = !inverse ? totalWidth : totalPreferred;
@@ -3323,6 +3347,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
};
adjustSizes(target, r, inverse);
columnWidthsInitialized = true;
}
@@ -3821,6 +3846,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
if (columnModel == null) {
throw new IllegalArgumentException("Cannot set a null ColumnModel");
}
columnWidthsInitialized = false;
TableColumnModel old = this.columnModel;
if (columnModel != old) {
if (old != null) {
@@ -4634,6 +4660,10 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
* @see TableColumnModelListener
*/
public void columnAdded(TableColumnModelEvent e) {
if (columnWidthsInitialized) {
TableColumn column = columnModel.getColumn(e.getToIndex());
column.setWidth(column.getPreferredWidth());
}
// If I'm currently editing, then I should stop editing
if (isEditing()) {
removeEditor();
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8234071 8387267
* @summary AUTO_RESIZE_LAST_COLUMN should resize only the last column during table layout
* @run main TestAutoResizeLastColumn
*/
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumnModel;
public class TestAutoResizeLastColumn {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(TestAutoResizeLastColumn::testLastColumnOnly);
}
private static void testLastColumnOnly() {
JTable table = new JTable(3, 3);
table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
if (table.getTableHeader().getResizingColumn() != null) {
throw new RuntimeException(
"AUTO_RESIZE_LAST_COLUMN must not set resizingColumn");
}
TableColumnModel cm = table.getColumnModel();
for (int i = 0; i < cm.getColumnCount(); i++) {
cm.getColumn(i).setMinWidth(10);
cm.getColumn(i).setPreferredWidth(100);
cm.getColumn(i).setWidth(100);
}
table.setSize(300, 100);
table.doLayout();
assertWidth(cm, 0, 100);
assertWidth(cm, 1, 100);
assertWidth(cm, 2, 100);
table.setSize(360, 100);
table.doLayout();
/*
* AUTO_RESIZE_LAST_COLUMN means the +60 delta is absorbed by
* the last column only.
* Without fix all columns width will change to 120.
*/
assertWidth(cm, 0, 100);
assertWidth(cm, 1, 100);
assertWidth(cm, 2, 160);
table.setSize(330, 100);
table.doLayout();
assertWidth(cm, 0, 100);
assertWidth(cm, 1, 100);
assertWidth(cm, 2, 130);
}
private static void assertWidth(TableColumnModel cm, int column, int expected) {
int actual = cm.getColumn(column).getWidth();
if (actual != expected) {
throw new RuntimeException(
"Unexpected width for column " + column
+ ": expected " + expected
+ ", actual " + actual);
}
}
}