Java - 如何防止单击第二个单元格时 JTable 中的水平自动滚动?

Java - How to prevent the horizontal auto-scrolling in a JTable when clicking the 2nd cell?

我有一个包含 2 列的 JTable。第二列的某些单元格中有长项,因此我使用水平滚动条,以便用户可以手动滚动它以查看那些长单元格中写的内容。

以下是 JTable 在单击其任何行之前的外观:

问题是,当我左键单击第二列中的任何单元格以突出显示该行时,table 会自动水平滚动,如下所示:

有没有办法防止这种自动滚动,但同时保持手动用户滚动(以防用户想水平滚动以查看单元格内的内容)?

也许您可以使用 Fixed Column Table 中的方法。

它允许您为滚动窗格创建一个"row header"。 header 行永远不会滚动,因此第一列将始终可见。但是,您仍然可以滚动浏览剩余的列。

您可以@Override table 的scrollRectToVisible 方法。作为第一步,我会使用一个空的实现。当您确切地弄清楚什么时候需要 auto-scrolling 什么时候不需要时,相应地实施该方法。

如果你想完全禁用自动滚动,你可以使用

table.setAutoscroll(false)

但实际上,这不是很有用,因为键盘导航正在关闭。如果单元格完全隐藏在视图之外,我建议您仍然自动滚动。为此,我禁用了自动滚动并重写了 changeSelection 来处理隐藏单元格时的滚动。

public static class TestTable extends JTable {
    static final int THRESHOLD = 10;
    static String[] columns = {"name", "description", "other"};
    static String[][] data = {
            {"name1", "some description 1", "other value we don't care about"},
            {"name2", "some description 2", "other value we don't care about"},
            {"name3", "some description 3", "other value we don't care about"}
    };

    public TestTable() {
        super(data, columns);
        setAutoResizeMode(AUTO_RESIZE_OFF);
        setAutoscrolls(false);

        getColumnModel().getColumn(0).setPreferredWidth(300);
        getColumnModel().getColumn(1).setPreferredWidth(300);
        getColumnModel().getColumn(2).setPreferredWidth(300);
    }

    @Override
    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
        super.changeSelection(rowIndex, columnIndex, toggle, extend);
        scrollColumnToVisible(rowIndex, columnIndex);
    }

    private void scrollColumnToVisible(int rowIndex, int columnIndex) {
        Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);

        int leftX = cellRect.x;
        int rightX = cellRect.x + cellRect.width;

        //assuming we're in scroll pane
        int width = Math.min(getWidth(), getParent().getWidth());

        int scrolledX = -getX();
        int visibleLeft = scrolledX;
        int visibleRight = visibleLeft + width;

        //bonus, scroll if only a little of a column is visible
        visibleLeft += THRESHOLD;
        visibleRight -= THRESHOLD;

        boolean isCellVisible = leftX < visibleRight // otherwise cell is hidden on the right
                && rightX > visibleLeft // otherwise cell is hidden on the left
                ;
        if (!isCellVisible) {
            scrollRectToVisible(cellRect);
        }
    }
}

作为奖励,我添加了 THRESHOLD 来考虑隐藏单元格,而实际上只有一小部分是可见的:)完整代码是 here.

JTable 的自动滚动行为在 changeSelection() 中实现。因此,防止水平自动滚动的最简单方法是始终将其绑定到第 0 列:

table = new JTable(new MyTableModel()) {
    @Override
    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
        super.changeSelection(rowIndex, 0, toggle, extend);
    }
};

如果你想禁用水平自动滚动,试试这个。

public class MyTable extends JTable {
    @Override
    public void scrollRectToVisible(Rectangle aRect) {
        aRect.x = 0;
        super.scrollRectToVisible(aRect);
    }
}