Problem with JTable.doLayout()

I'm trying to extend JTable so I can have weighted column widths. To do so I have overriddenJTable.doLayout(). It works perfect except the program flow never reachessetValue() of the table model and I can't understand why not.

Can any of you shed some light on this?

Thanks.

Test program:publicclass TestFrameextends javax.swing.JFrame{

public TestFrame(){

initComponents();

MyTable jTable1 =new MyTable();

jTable1.setModel(new MyTableModel());

jTable1.setPreferredWidths(newint[]{1, 1, 2});

jScrollPane1.setViewportView(jTable1);

setSize(400, 200);

setLocationRelativeTo(null);

}

privatevoid initComponents(){

buttonGroup1 =new javax.swing.ButtonGroup();

jPanel1 =new javax.swing.JPanel();

jLabel1 =new javax.swing.JLabel();

jRadioButton1 =new javax.swing.JRadioButton();

jRadioButton2 =new javax.swing.JRadioButton();

jScrollPane1 =new javax.swing.JScrollPane();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

jLabel1.setText("Weighted column widths");

jPanel1.add(jLabel1);

buttonGroup1.add(jRadioButton1);

jRadioButton1.setSelected(true);

jRadioButton1.setText("on");

jRadioButton1.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));

jRadioButton1.setMargin(new java.awt.Insets(0, 0, 0, 0));

jRadioButton1.addActionListener(new java.awt.event.ActionListener(){

publicvoid actionPerformed(java.awt.event.ActionEvent evt){

jRadioButton1ActionPerformed(evt);

}

});

jPanel1.add(jRadioButton1);

buttonGroup1.add(jRadioButton2);

jRadioButton2.setText("off");

jRadioButton2.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));

jRadioButton2.setMargin(new java.awt.Insets(0, 0, 0, 0));

jRadioButton2.addActionListener(new java.awt.event.ActionListener(){

publicvoid actionPerformed(java.awt.event.ActionEvent evt){

jRadioButton2ActionPerformed(evt);

}

});

jPanel1.add(jRadioButton2);

getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH);

getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);

pack();

}

privatevoid jRadioButton2ActionPerformed(java.awt.event.ActionEvent evt){

useWeighted = jRadioButton1.isSelected();

}

privatevoid jRadioButton1ActionPerformed(java.awt.event.ActionEvent evt){

useWeighted = jRadioButton1.isSelected();

}

publicstaticvoid main(String args[]){

java.awt.EventQueue.invokeLater(new Runnable(){

publicvoid run(){

new TestFrame().setVisible(true);

}

});

}

private javax.swing.ButtonGroup buttonGroup1;

private javax.swing.JLabel jLabel1;

private javax.swing.JPanel jPanel1;

private javax.swing.JRadioButton jRadioButton1;

private javax.swing.JRadioButton jRadioButton2;

private javax.swing.JScrollPane jScrollPane1;

privateboolean useWeighted =true;

class MyTableModelextends javax.swing.table.DefaultTableModel{

public MyTableModel(){

super(new Object[][]{{ null, null, null,null},{ null, null, null,null}},

new String[]{"Title 1","Title 2","Title 3","Title 4"});

}

@Override

publicvoid setValueAt(Object aValue,int row,int column){

super.setValueAt(aValue, row, column);

System.out.println("Setting value=" + aValue +" at (" + row +", " + column +")");

}

}

class MyTableextends javax.swing.JTable{

privateint[] weights;

publicvoid setPreferredWidths(int[] weights){

this.weights = weights;

}

@Override

publicvoid doLayout(){

if (tableHeader !=null && getTableHeader().getResizingColumn() !=null){

System.out.println("Resizing column");

super.doLayout();

}elseif (weights ==null || weights.length == 0){

System.out.println("no weights defined");

super.doLayout();

}else{

if (useWeighted){

System.out.println("doing layout with weights");

int totalWeight = 0;

javax.swing.table.TableColumnModel columnModel = getColumnModel();

int columnCount = columnModel.getColumnCount();

int weightCount = columnCount < weights.length ? columnCount : weights.length;

for (int i = 0; i < weightCount; i++){

totalWeight += weights[i];

}

int tableWidth = getWidth();

for (int i = 0; i < columnCount; i++){

int weight = 1;

if (i < weights.length){

weight = weights[i];

}

javax.swing.table.TableColumn column = columnModel.getColumn(i);

int width = tableWidth * weight / totalWeight;

column.setWidth(width);

column.setPreferredWidth(width);

}

}

super.doLayout();

}

}

}

}

[9766 byte] By [NickDGa] at [2007-11-27 8:06:03]
# 1

> never reaches setValue() of the table model

Well, actually it does. If you start typing in a cell the setValue() method will be invoked and if you use the F2 key to start editing it will work as well.

However, if you try double clicking on the cell to start editing it doesn't work. I don't know why.

> I'm trying to extend JTable so I can have weighted column widths. To do so I have overridden JTable.doLayout()

I am not sure you need to reset the weights every time the table is resized. I opened up two frames and set the widths equal. Then on one of the frames I clicked the "off" button. Then I started to increase/decrease the width of each frame at the same time. As far as I could tell respective columns in each frame resized the same.

So it would seem to me that you only need to reset the weighted values once when the radio button is click and let the default sizing behaviour size the columns when the table size is changes. In other words move the sizing code from the doLayout() method to the actionPerformed() method.

I know it doesn't answer your question, but it may help with a solution.

camickra at 2007-7-12 19:48:35 > top of Java-index,Desktop,Core GUI APIs...
# 2

> > never reaches setValue() of the table model

>

> Well, actually it does. If you start typing in a cell

> the setValue() method will be invoked and if you use

> the F2 key to start editing it will work as well.

I didn't notice that.

> However, if you try double clicking on the cell to

> start editing it doesn't work. I don't know why.

Apparently, double-clicking causes revalidation which calls doLayout(). But I don't need to redo the layout myself if the total width hasn't changed, so I modified doLayout:if (getColumnModel().getTotalColumnWidth() == getWidth()) {

super.doLayout();

} else if (tableHeader != null ...

> > I'm trying to extend JTable so I can have weighted

> column widths. To do so I have overridden

> JTable.doLayout()

>

> I am not sure you need to reset the weights every time the table is resized.

> I opened up two frames and set the widths equal. Then on one of the

> frames I clicked the "off" button. Then I started to increase/decrease the

> width of each frame at the same time. As far as I could tell respective

> columns in each frame resized the same.

It only seems to be the same. With the weights I defined in the example the difference isn't as pronounced but if you put e.g. 10 instead of 3 as the last weight, you'll see the difference.

The default implementation distributes the changes equally over all columns but I don't want that, I want to keep the ratio defined by the weights.

I also found another small bug: if I resized the columns myself and then resize the frame, the columns are laid out as defined by the weights. That's not right so I added a check that when the column widths are user defined, I'll use default layout. Better would be to also resize the columns using the weights, but the added value would be limited and I don't have the time to study it.

So the complete table looks like this:class MyTable extends javax.swing.JTable {

private int[] weights;

private boolean userDefinedColumnWidth = false;

public void setPreferredWidths(int[] weights) {

this.weights = weights;

}

@Override

public void doLayout() {

if (getColumnModel().getTotalColumnWidth() == getWidth()) {

super.doLayout();

} else if (tableHeader != null && getTableHeader().getResizingColumn() != null) {

System.out.println("Resizing column");

userDefinedColumnWidth = true;

super.doLayout();

} else if (weights == null || weights.length == 0) {

System.out.println("no weights defined");

super.doLayout();

} else {

if (useWeighted && !userDefinedColumnWidth) {

System.out.println("doing layout with weights");

int totalWeight = 0;

javax.swing.table.TableColumnModel columnModel = getColumnModel();

int columnCount = columnModel.getColumnCount();

int weightCount = columnCount < weights.length ? columnCount : weights.length;

for (int i = 0; i < weightCount; i++) {

totalWeight += weights[i];

}

int tableWidth = getWidth();

for (int i = 0; i < columnCount; i++) {

int weight = 1;

if (i < weights.length) {

weight = weights[i];

}

javax.swing.table.TableColumn column = columnModel.getColumn(i);

int width = tableWidth * weight / totalWeight;

column.setWidth(width);

column.setPreferredWidth(width);

}

}

super.doLayout();

}

}

}

NickDGa at 2007-7-12 19:48:35 > top of Java-index,Desktop,Core GUI APIs...