JTable在扩展后无法向下滚动?

时间:2016-07-17 18:51:52

标签: java swing jtable

我已经扩展了JTable,因此它可以按字母顺序对数据进行排序,并根据第一个字母按部分分隔数据。

See this question and marked answer for more clarification

扩展表工作正常。但是,在排序时,通过单击表格的标题,我在向下滚动表格时遇到问题(使用鼠标滚轮)。 enter image description here

这是扩展表的代码。 (注意:您也可以在上面的超链接中找到此代码。)

import java.awt.BorderLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableModel;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableModel;



public class SectionedTable
        extends JTable {

    private static final long serialVersionUID = 1;

    private final NavigableMap<Integer, String> sectionHeadings
            = new TreeMap<>();

    private final NavigableMap<Integer, Integer> rowTopEdges
            = new TreeMap<>();

    // Used when calling SwingUtilities.layoutCompoundLabel.
    private final Rectangle iconBounds = new Rectangle();
    private final Rectangle textBounds = new Rectangle();

    public SectionedTable() {
        init();
    }

    public SectionedTable(TableModel model) {
        super(model);
        init();
    }

    private void init() {
        setShowGrid(false);
        setAutoCreateRowSorter(true);

        recomputeSections();
        recomputeRowPositions();
    }

    private void recomputeSections() {
        if (sectionHeadings == null) {
            return;
        }

        sectionHeadings.clear();

        RowSorter<? extends TableModel> sorter = getRowSorter();
        if (sorter == null) {
            return;
        }

        for (RowSorter.SortKey key : sorter.getSortKeys()) {
            SortOrder order = key.getSortOrder();
            if (order != SortOrder.UNSORTED) {
                int sortColumn = key.getColumn();

                String lastSectionStart = "";
                int rowCount = getRowCount();
                for (int row = 0; row < rowCount; row++) {
                    System.out.println("row er    : " + row);
                    System.out.println("rowcount er   : " + rowCount);
                    System.out.println("sortColumn er  :   " + sortColumn);
                    Object value = getValueAt(row, sortColumn);
                    if (value == null) {
                        value = "?";
                    }

                    String s = value.toString();
                    if (s.isEmpty()) {
                        s = "?";
                    }

                    String sectionStart = s.substring(0,
                            s.offsetByCodePoints(0, 1));
                    sectionStart = sectionStart.toUpperCase();

                    if (!sectionStart.equals(lastSectionStart)) {
                        sectionHeadings.put(row, sectionStart);
                        lastSectionStart = sectionStart;
                    }
                }
                break;
            }
        }
    }

    private void recomputeRowPositions() {
        if (rowTopEdges == null) {
            return;
        }

        rowTopEdges.clear();

        int y = getInsets().top;
        int rowCount = getRowCount();
        int rowHeight = getRowHeight();
        for (int row = 0; row < rowCount; row++) {
            rowTopEdges.put(y, row);
            y += getRowHeight(row);
            if (sectionHeadings.containsKey(row)) {
                y += rowHeight;
            }
        }
    }

    @Override
    public void tableChanged(TableModelEvent event) {
        //super.tableChanged(event);
        recomputeSections();
        recomputeRowPositions();
        super.tableChanged(event);
    }

    @Override
    public void sorterChanged(RowSorterEvent event) {
        recomputeSections();
        recomputeRowPositions();
        super.sorterChanged(event);
    }

    @Override
    public void validate() {
        super.validate();
        recomputeRowPositions();
    }

    @Override
    public int rowAtPoint(Point location) {
        Map.Entry<Integer, Integer> entry = rowTopEdges.floorEntry(location.y);
        if (entry != null) {
            int row = entry.getValue();
            return row;
        }
        return -1;
    }

    @Override
    public Rectangle getCellRect(int row,
            int column,
            boolean includeSpacing) {

        Rectangle rect = super.getCellRect(row, column, includeSpacing);

        int sectionHeadingsAbove = sectionHeadings.headMap(row, true).size();
        rect.y += sectionHeadingsAbove * getRowHeight();

        return rect;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        boolean ltr = getComponentOrientation().isLeftToRight();

        int rowHeight = getRowHeight();
        FontMetrics metrics = g.getFontMetrics();
        int ascent = metrics.getAscent();
        for (Map.Entry<Integer, String> entry : sectionHeadings.entrySet()) {
            int row = entry.getKey();
            String heading = entry.getValue();

            Rectangle bounds = getCellRect(row, 0, true);
            bounds.y -= rowHeight;
            bounds.width = getWidth();
            bounds.grow(-6, 0);

            iconBounds.setBounds(0, 0, 0, 0);
            textBounds.setBounds(0, 0, 0, 0);
            String text = SwingUtilities.layoutCompoundLabel(this,
                    metrics, heading, null,
                    SwingConstants.CENTER, SwingConstants.LEADING,
                    SwingConstants.CENTER, SwingConstants.CENTER,
                    bounds, iconBounds, textBounds, 0);

            g.drawString(text, textBounds.x, textBounds.y + ascent);

            int lineY = textBounds.y + ascent / 2;
            if (ltr) {
                g.drawLine(textBounds.x + textBounds.width + 12, lineY,
                        getWidth() - getInsets().right - 12, lineY);
            } else {
                g.drawLine(textBounds.x - 12, lineY,
                        getInsets().left + 12, lineY);
            }
        }
    }

    public static void main(String[] args) {

        DefaultTableModel model;
        Object[][] data = new Object[50][5];
        String[] columnNames = {"First Name",
            "Last Name",
            "Sport",
            "# of Years",
            "Vegetarian"};

        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 5; j++) {
                data[i][j] = "Amy";
            }
        }

        for (int i = 10; i < 20; i++) {
            for (int j = 0; j < 5; j++) {
                data[i][j] = "Bob";
            }
        }

        for (int i = 20; i < 30; i++) {
            for (int j = 0; j < 5; j++) {
                data[i][j] = "Joe";
            }
        }

        for (int i = 30; i < 50; i++) {
            for (int j = 0; j < 5; j++) {
                data[i][j] = "M";
            }
        }

        SectionedTable table = new SectionedTable();
        model = new DefaultTableModel(data, columnNames);
        table.setModel(model);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                JTable table = new SectionedTable();
                table.setModel(model);
                JScrollPane scrollPane = new JScrollPane(table);
                frame.add(scrollPane, BorderLayout.CENTER);
                frame.setSize(500, 500);
                frame.setVisible(true);
            }
        });
    }
}

我一直在努力找出可能导致这个问题的原因,而我并没有接近任何解决方案。我想它可能在rowAtPoint()或getCellRect(),但我不确定。有人可以发现这个问题可能存在于代码中吗?

1 个答案:

答案 0 :(得分:2)

我注意到当滚动停止运行时getScrollableUnitIncrement(...)方法返回0

作为一个快速黑客,我在桌面上添加了以下内容:

@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
{
    int increment = super.getScrollableUnitIncrement(visibleRect, orientation, direction);

    if (increment == 0)
        increment = 16;

    return increment;
}

不知道是否会引起其他问题。 由此我能够确定返回0,因此没有滚动。