获取和设置 JScrollBar 在 Java Swing 中的位置

Get and set JScrollBar position in Java Swing

我有一个 JTable 视图,它是从数据库检索的大量数据的视图。

出于这个原因,我想只显示这些数据的一部分(例如前 100 行),当用户使用 JScrollBar 到达 JTable 的末尾时,JTable 将显示其他行。

所以我正在寻找一种机制,让我知道滚动条何时位于 JTable 的末尾,并且仅在那一刻执行另一个查询。而且,当我得到新的 List 时,将滚动条位置设置为新查询之前的位置,只是为了给用户一个 "continuity"。

任何人都可以提供一些完成此任务的提示吗?

先谢谢你

如您之前所见,大多数 JComponents 都有 models 并且它们是根据它们的模型呈现的。因此,如果您可以访问 model,您就可以访问您需要的事件和数据。

据此,JScrollBar也遵循这个规律,有自己的模式。通过获取此模型(这是一个 BoundedRangeModel)并添加一个 ChangeListener,您可以创建所需的内容以从数据库中检索下一页数据。

重要的一点是找到支配 JScrollBar 模型的规则。 BoundedRangeModel 有一些属性可以参考。在这种情况下,其中一些对您很重要的是:

  • valueIsAdjusting
  • value
  • extent
  • maximum

ValueIsAdjusting 表示我们是否正在更改 BoundedRangeModel 的范围。说白了就是:scrollBar被拖了?

其他属性 valueextentmaximum 是您可以用来查明 ScrollBar 是否到达范围末尾的属性。如果Scrollbar到达那里,就是从数据库中检索下一页数据的时候了。为了表明这种情况,必须应用以下等式:

value + extent = maximum

以下代码片段可以澄清上述解释:

import java.awt.BorderLayout;

import javax.swing.BoundedRangeModel;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableModel;

public class LiveJTableDemoFrame extends JFrame {
    private static final int FRAME_HEIGHT = 200;
    private static final int FRAME_WIDTH = 400;
    //
    private JTable table;
    private String[] columnNames;
    private DefaultTableModel tableModel;

    public LiveJTableDemoFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(FRAME_WIDTH, FRAME_HEIGHT);
        //
        columnNames = new String[]{"ID", "A", "B", "C", "D"};
        //
        tableModel = new DefaultTableModel(columnNames, 0); 
        table = new JTable(tableModel);
        //
        final JScrollPane p = new JScrollPane();
        p.setViewportView(table);
        p.getVerticalScrollBar().getModel().addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                BoundedRangeModel scModel = p.getVerticalScrollBar().getModel();
                boolean valueIsAdjusting = scModel.getValueIsAdjusting();
                if(!valueIsAdjusting){
                    if(scModel.getValue() + scModel.getExtent() == scModel.getMaximum()){
                        retrieveData();
                    }
                }
            }
        });
        //
        retrieveData();
        //
        this.setLayout(new BorderLayout());
        this.add(p, BorderLayout.CENTER);
    }

    //Dummy method to simulate retrieving data from database
    private void retrieveData(){
        for (int i = 0; i < 10; i++){
            Object[] rowData = new Object[columnNames.length];
            //
            rowData[0] = tableModel.getDataVector().size();
            rowData[1] = "A";
            rowData[2] = "B";
            rowData[3] = "C";
            rowData[4] = "D";
            //
            tableModel.addRow(rowData); 
        }
        //tableModel.fireTableDataChanged();
    }

    public static void main(String[] args) {
        new LiveJTableDemoFrame().setVisible(true);
    }
}

[更新]

另一种方法是在垂直 JScrollBar 上添加一个 AdjustmentListener 并使用事件获取 valueValueIsAdjusting。此外,您还必须从 JScrollBarmodel 中获取 extentmaximum。以下代码段显示了替代方法:

    final JScrollPane p = new JScrollPane();
    p.setViewportView(table);
    p.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener(){ 
        @Override
        public void adjustmentValueChanged(AdjustmentEvent e) {
            // here the control if vertical scroll bar has reached the maximum value
            if(!e.getValueIsAdjusting()){
                JScrollBar source = (JScrollBar) e.getAdjustable();
                int extent = source.getModel().getExtent();
                int maximum = source.getModel().getMaximum();
                if(e.getValue() + extent == maximum){
                    retrieveData();
                }
            }

        }
    });

祝你好运。