具备自动调整大小、水平滚动和可收缩第一列的JTable

5

我在创建带滚动条的JTable时遇到了问题。我想要一个有两列且没有可见滚动条的JTable。

如果我放大其中一列,滚动条应该变为可见状态并且列会自动调整大小。

我按照这篇答案(如何使JTable既可以自适应又可以水平滚动)来实现,这基本上是:

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

然而,使用此解决方案,我无法缩小第一列。只有当我扩大第二列并滚动条变得可见时,我才能缩小第一列。

所需的行为是使两个列自动可调整大小。也就是说,第一列可以缩小、延伸而不会弹出滚动条。只有在扩展其中一个列,以便视图应该扩展时,滚动条才会弹出。

一个场景:

  1. 缩小第一列->第二列变大,没有滚动条
  2. 放大第一列->第二列变小,仍然没有滚动条
  3. 放大第二列->第一列保持不变,第二列变大且滚动条出现

有什么修复的想法吗?

一个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";
}
}
}

重写scrollableTracksViewportWidth不应影响列的可调整大小性。你的代码是否操作了第一个TableColumn的minWidth、maxWidth或resizable属性? - VGR
没有代码可以操作那个。有一个AbstractTableModel,它需要一个值列表来填充表格。此外,表格被包装在JScrollPane中,就是这样。 - chillx
为了更快地获得更好的帮助,请发布一个SSCCE - Andrew Thompson
在编辑时看到:不支持JXTable - 当缩小第一列时,其他列会被扩展,将它们缩小回初始大小需要额外的逻辑(不确定这有多难,调整大小逻辑非常复杂)。 - kleopatra
2个回答

7

仅重写getTracks方法是不够的,如果需要进行跟踪,则还需要欺骗超类的布局以执行正确的操作。

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();
    }

};

这可能并不完全(即使在编辑时处理了columnMarginChanged的复制,从支持该行为的JXTable (来自SwingX项目)中),它通过附加的布局属性来支持。

xTable.setHorizontalScrollEnabled(true);

1
有没有想法能否缩小秒数列?将调整模式更改为“ALL”而不是“SUBSEQUENT”。 - camickr
1
在原始问题中,OP只有两列。当没有水平滚动条时,您无法缩小第二列,因为SUBSEQUENT没有地方来分配额外的空间。当您使用ALL时,第一列可以增加,而第二列会缩小。 - camickr
@kleopatra 不好意思,我是指要与jdialog的高度相适应,我重写了JDialog#getPreferredSize()方法并且它起作用了,但是总是显示滚动条,我希望例如20行适应而不需要滚动条,对于这个代码的宽度来说很好:D +1 - nachokk
@nachokk 使用 JXTable :) 然后您可以像这样配置它 xTable.setVisibleRowCount(20) - kleopatra
@kleopatra mm我替换了它,但在其他地方使用旧的东西会出现一些错误,所以这不是一个选项,但无论如何谢谢你,我感激你的帮助。如果我有时间,我会做一些研究来解决这个问题 :) - nachokk
显示剩余11条评论

1

在实施@kleopatra后,我注意到当您缩小一列的大小,然后再稍微增加一点点(这种情况很容易发生)时,会出现滚动条。因此,我略微修改了代码:

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

这样可以逐渐增加列的大小,而不会失去自动调整大小功能。
目前还不确定"50"这个神奇数字是否是一个好的度量标准,但在初步测试中效果相当不错。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接