I have created a JTreeTable
where the TreeCellRenderer
is a JTable
. This allows me to have different TableColumnModel
s for each row. Siblings of the JTree
share a TableColumnModel
. It works great. I can select a row and show a different set of columns without actually changing the the data in the other rows even at different levels.
I have a problem though where when select a different row the JTable is changing my TableColumn
s width and setting it to the preferred size. So the effect is that dragging the width of one column and then selecting a different row set it back to the preferred size.
I have tried a number of things to fix this, including adding a TableColumnModelListener
and when I change the width I set the preferred size of the column. This doesn't work because the JTable is setting the preferred size to 15 after I change it.
I have traced the code back to what is causing this. It is the JTable.doLayout()
method causing my grief. That method is calling the private method setWidthsFromPreferredWidths(...)
. This method is what is setting my TableColumn widths.
I tried overriding the doLayout()
method since it is public but I could not make the call to super.doLayout()
when I am already overriding the method. Not calling that causes some very weird UI issues as you could imagine. I also tried casting this
to the superclass of JTable
which is JComponent
but I end up with a stack overflow error. This does not feel like the right solution here anyway.
What I think is happening is that because my JTable
is inside of a panel as the renderer of a tree cell instead of inside of a scrollpane, that something is going wrong with the layout.I don't know for sure though. Below is the code inside of the private method I referenced above:
private void setWidthsFromPreferredWidths(final boolean inverse) {
int totalWidth = getWidth();
int totalPreferred = getPreferredSize().width;
int target = !inverse ? totalWidth : totalPreferred;
final TableColumnModel cm = columnModel;
Resizable3 r = new Resizable3() {
public int getElementCount() { return cm.getColumnCount(); }
public int getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
public int getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
public int getMidPointAt(int i) {
if (!inverse) {
return cm.getColumn(i).getPreferredWidth();
}
else {
return cm.getColumn(i).getWidth();
}
}
public void setSizeAt(int s, int i) {
if (!inverse) {
cm.getColumn(i).setWidth(s);
}
else {
cm.getColumn(i).setPreferredWidth(s);
}
}
};
adjustSizes(target, r, inverse);
}
Looking at the code, I think what's happening is that the getWidth()
method is causing the JTable to want to resize the columns to the preferredsize because it thinks it doesn't have enough room. I tried just copy pasting this method locally but since there are private methods involved and it kept getting deeper and deeper I stopped that. The intention was to try to debug why it is choose to adjust the width. If I can address the root cause, that may be the best solution for this.
The JTree
itself is inside of JScrollPane
. The JTableHeader
is set to the ViewPortColumnHeaderView
. Below are 2 images where I am selecting different rows. Ignore the header alignment, I already have a solution for that just did not implement it entirely yet.
Any thoughts on the problem would be greatly appreciated. Also happy to post any code you think might be useful if you think it will help.