简体   繁体   中英

JTable with autoresize, horizontal scrolling and shrinkable first column

I am having trouble creating a JTable with scrollbars. I want a JTable with 2 columns and no visible scrollbars.

If I enlarge one of the columns the scrollbars should become visible and the columns resize.

I followed this answer How to make JTable both AutoResize and horizontall scrollable? and works fine which basically comes down to:

JTable table = new JTable() {
  @Override
  public boolean getScrollableTracksViewportWidth() {
    return getPreferredSize().width < getParent().getWidth();
  }
};
table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );

However, with this solution I cannot shrink the first column. Only if I enlarge the 2nd column and the scrollbars become visible I can shrink the first one.

The required behavior is that the 2 columns are automatically resizable. Meaning that the 1 column can shrink and afterwards extend without the scrollbars popping up. Only when extending one of the columns, so that the view should extend, the scrollbars should pop up.

A scenario:

  1. Shrink the 1st column -> 2nd one enlarges, no scrollbars
  2. Enlarge the 1st column -> 2nd one shrinks, still no scrollbars
  3. Enlarge the 2nd column -> 1 column stays the same, 2nd one enlarges and scrollbars appear

Any ideas on fixing this?

An SSCCE:

import javax.swing.JDialog;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;
import java.awt.BorderLayout;
import java.awt.Container;

public class TableTest {
public TableTest() {

JDialog mainDialog = new JDialog();
mainDialog.setResizable( true );
mainDialog.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
Container contentPane = mainDialog.getContentPane();

JTable myTable = new JTable() {
  @Override
  public boolean getScrollableTracksViewportWidth() {
    return getPreferredSize().width < getParent().getWidth();
  }
};

myTable.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
myTable.setModel( new MyTableModel() );
JScrollPane scrollPane = new JScrollPane( myTable );
contentPane.add( scrollPane, BorderLayout.CENTER );

mainDialog.pack();
mainDialog.setVisible( true );
}

public static void main( String[] args ) {
new TableTest();
}

private class MyTableModel extends AbstractTableModel {

@Override public int getRowCount() {
  return 1;
}

@Override public int getColumnCount() {
  return 2;
}

@Override public Object getValueAt( int rowIndex, int columnIndex ) {
  return "ARandomValue";
}
}
}

It's not quite enough to override the getTracks method, you have to fool super's layout into doing the right-thingy if tracking:

JTable myTable = new JTable(10, 4) {
    private boolean inLayout;

    @Override
    public boolean getScrollableTracksViewportWidth() {
        return hasExcessWidth();

    }


    @Override
    public void doLayout() {
        if (hasExcessWidth()) {
            // fool super
            autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
        }
        inLayout = true;
        super.doLayout();
        inLayout = false;
        autoResizeMode = AUTO_RESIZE_OFF;
    }


    protected boolean hasExcessWidth() {
        return getPreferredSize().width < getParent().getWidth();
    }

    @Override
    public void columnMarginChanged(ChangeEvent e) {
        if (isEditing()) {
            // JW: darn - cleanup to terminate editing ...
            removeEditor();
        }
        TableColumn resizingColumn = getTableHeader().getResizingColumn();
        // Need to do this here, before the parent's
        // layout manager calls getPreferredSize().
        if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
                && !inLayout) {
            resizingColumn.setPreferredWidth(resizingColumn.getWidth());
        }
        resizeAndRepaint();
    }

};

Might not be entirely complete (probably still isn't, even after the edit to take care of columnMarginChanged, copied from JXTable (of the SwingX project ) which support that behaviour by an additional layout property

xTable.setHorizontalScrollEnabled(true);

With the implementation of @kleopatra, I noticed that you get a scrollbar, when you reduce the size of a column and then increase it again just slightly (which happens quite often by accident). So I've slightly changed the code slightly:

protected boolean hasExcessWidth() {
    return getPreferredSize().width - getParent().getWidth() < 50;
}

This allows to slowly increase the size of a column without loosing the auto resize.

Not really sure yet if the magic "50" is a good measurement, but works quite well in initial tests

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM