如何在滚动窗格内冻结JTable行选择 [英] How can I freeze a JTable row selection inside a scroll pane

查看:111
本文介绍了如何在滚动窗格内冻结JTable行选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个经常更新的JTable.它位于滚动窗格中.

I've got a JTable that updates frequently. It sits inside of a scroll pane.

有时,我们会看到一条消息,我们希望对其进行更深入的研究.不幸的是,由于更新数量众多,该消息将在可见屏幕上滚动下来,然后我们才能完成查看.

Occasionally we'll see a message that we'd like to dig deeper into. Unfortunately due to the number of updates the message will scroll off the visible screen before we can finish looking at it.

我希望能够在检查消息时冻结视口/滚动,但仍允许表模型随新消息一起更新.

I'd like to be able to freeze the viewport/scrolling while we examine the message but still allow the table model to update with new messages.

我可以使用以下代码将所选行转到顶部:

I can get the selected row to go to the top with this code:

        int firstSelectedRow = table.getSelectedRow();
        Rectangle rowLocation = table.getCellRect(firstSelectedRow, 0, false);
        scroll.getVerticalScrollBar().setValue(rowLocation.y);
        freezeScrolling.setText("Resume Updates");

但这仅在按下按钮时发生,然后迅速滚开.

but that only happens on button press and then it quickly sscrolls away.

是否有一种方法可以告诉视口/滚动窗格冻结选择,然后将其关闭以使滚动窗格按您的期望进行更新?

Is there a way to tell the viewport/scroll pane to freeze on a selection and the to turn it off so that the scroll pane updates as you'd expect?

推荐答案

好的,这个让我很开心,所以我花了一些时间来找到解决这个问题的方法.我找到了两个选择:

OK, this one teased me a lot, so I spent some time to find a way for this. I found two options:

  1. 我喜欢的那个是因为我发现它更简单:将新条目阻止到表模型中并将它们存储在缓冲区中.每当我们解冻时,就会将缓冲区刷新到表模型.
  2. 第二个选项包括定位当前的顶部可见行.如果用户滚动,我们将捕获最上方的可见行.随着模型更新,我们在表中找到捕获的行,并将视口位置设置为该行.

这里是一个SSCCE,它说明了两种机制(不要介意代码设计的繁琐性,我测试了很多东西-扩展JScrollPane实际上不是一个好主意,可以全部在外部完成). /p>

Here is an SSCCE that illustrates both mechanisms (don't mind the crapiness of the code design, I tested a bunch of stuffs -- extending the JScrollPane is actually not a good idea, it can all be done externally).

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

public class Tables {

    private static class JScrollPaneExtension extends JScrollPane implements TableModelListener, AdjustmentListener {
        private boolean frozen = false;
        private Vector<String> rowData;
        private final JTable table;
        private final MyTableModel tableModel;

        private JScrollPaneExtension(JTable table, MyTableModel tableModel) {
            super(table);
            this.table = table;
            this.tableModel = tableModel;
            tableModel.addTableModelListener(this);
            getVerticalScrollBar().addAdjustmentListener(this);
        }

        public boolean isFrozen() {
            return frozen;
        }

        public void setFrozen(boolean frozen) {
            if (frozen != this.frozen) {
                this.frozen = frozen;
                if (frozen) {
                    captureCurrentTopRowData();
                } else {
                    rowData = null;
                }
            }
        }

        private void captureCurrentTopRowData() {
            int row = table.rowAtPoint(getViewport().getViewPosition());
            if (row > -1) {
                rowData = (Vector<String>) tableModel.getDataVector().get(row);
            }
        }

        @Override
        public void adjustmentValueChanged(AdjustmentEvent e) {
            if (frozen) {
                captureCurrentTopRowData();
                scrollToRowData();
            }
        }

        @Override
        public void tableChanged(TableModelEvent e) {
            scrollToRowData();
        }

        private void scrollToRowData() {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    if (frozen) {
                        int index = tableModel.getDataVector().indexOf(rowData);
                        getViewport().setViewPosition(table.getCellRect(index, 0, true).getLocation());
                    }
                }
            });
        }

    }

    public static class MyTableModel extends DefaultTableModel {
        private int count;

        private boolean frozen = false;

        private List<Vector<String>> buffer = new ArrayList<Vector<String>>();

        public MyTableModel() {
            addColumn("Test");
        }

        public void insertNewRow() {
            Vector<String> rowData = createNewRowData();
            if (isFrozen()) {
                buffer.add(rowData);
            } else {
                insertRow(0, rowData);
            }
        }

        private Vector<String> createNewRowData() {
            Vector<String> data = new Vector<String>(1);
            data.add("Hello-" + (count++));
            return data;
        }

        public boolean isFrozen() {
            return frozen;
        }

        public void setFrozen(boolean frozen) {
            if (frozen == this.frozen) {
                return;
            }
            this.frozen = frozen;
            if (!frozen) {
                flushBuffer();
            }
        }

        private void flushBuffer() {
            for (Vector<String> rowData : buffer) {
                insertRow(0, rowData);
            }
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final MyTableModel model = new MyTableModel();
        JTable table = new JTable(model);
        final JScrollPaneExtension scroll = new JScrollPaneExtension(table, model);
        JPanel panel = new JPanel();
        final JButton freeze = new JButton("Freeze");
        freeze.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                if (model.isFrozen()) {
                    freeze.setText("Freeze model");
                } else {
                    freeze.setText("Continue");
                }
                model.setFrozen(!model.isFrozen());
            }
        });
        final JButton freeze2 = new JButton("Freeze scroll");
        freeze2.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                if (scroll.isFrozen()) {
                    freeze2.setText("Freeze scroll");
                } else {
                    freeze2.setText("Resume scroll");
                }
                scroll.setFrozen(!scroll.isFrozen());
            }
        });
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        frame.add(scroll);
        panel.add(freeze);
        panel.add(freeze2);
        frame.getContentPane().add(panel, BorderLayout.NORTH);
        frame.pack();
        frame.setVisible(true);
        Timer t = new Timer();
        t.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        model.insertNewRow();
                    }
                });
            }
        }, new Date(), 300);
    }
}

这篇关于如何在滚动窗格内冻结JTable行选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆