我已经扩展了JTable,因此它可以按字母顺序对数据进行排序,并根据第一个字母按部分分隔数据。
See this question and marked answer for more clarification
扩展表工作正常。但是,在排序时,通过单击表格的标题,我在向下滚动表格时遇到问题(使用鼠标滚轮)。
这是扩展表的代码。 (注意:您也可以在上面的超链接中找到此代码。)
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(),但我不确定。有人可以发现这个问题可能存在于代码中吗?
答案 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
,因此没有滚动。