我想在最多50行的jtable中添加一个scroll to end(autoscroll)函数。autoscroll函数应该像intellij scroll to end一样工作。
最初有0行。在几毫秒(比如说100毫秒)内,一些项目(1-5个项目)被添加到表的末尾。如果表行数达到最大值(50),则在下一次插入之前将删除第一行。
当用户用鼠标拖动或滚轮滚动到最后时,选中滚动到最后复选框,功能将被启用。从那时起,滚动窗格应滚动到表的底部,如:
scrollRectToVisible(getCellRect(getRowCount() - 1, 0, true));
当用户通过拖动或鼠标滚轮更改滚动条位置而不是视口底部时,将取消选中“滚动到结尾”复选框,并禁用该功能。
如果未选中“滚动到结尾”复选框,则表格将对通过拖动或鼠标滚轮进行的滚动条移动做出React。但是视口应该显示相同的数据。
如果由于删除随后的第一行而无法在视口中显示相同的数据,则视口中可见的第一行数据将转到上一行。
这正是intellij控制台日志屏幕的行为。我写了scroll以结束启用功能(90%工作)。我不能写滚动结束禁用功能,我不知道保存当前视口如上所述。
谢谢你的帮助。
package org.example.table;
import com.bsbls.home.gui.test.GuiTester;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class MyTable extends JTable {
JScrollPane scrollPane;
boolean autoScroll;
private Consumer<Boolean> scrollToEndListener;
private Object lastValue;
private ScheduledFuture<?> future;
public MyTable(int max) {
this.setFillsViewportHeight(true);
this.setRowHeight(24);
this.setModel(new MyTableModel(max));
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
if (autoScroll) {
scrollToEnd();
}
}
});
}
public MyTableModel getTableModel() {
return (MyTableModel) getModel();
}
private void scrollToEnd() {
scrollRectToVisible(getCellRect(getRowCount() - 1, 0, true));
}
public void setScrollToEnd(boolean autoScroll) {
this.autoScroll = autoScroll;
if (autoScroll) {
scrollToEnd();
}
if (scrollToEndListener != null) {
scrollToEndListener.accept(autoScroll);
}
}
public void setScrollToEndListener(Consumer<Boolean> scrollToEndListener) {
this.scrollToEndListener = scrollToEndListener;
}
public JScrollPane wrap() {
if (scrollPane == null) {
scrollPane = new JScrollPane(this);
scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
scrollBar.addAdjustmentListener(e -> {
if (e.getValue() + scrollBar.getVisibleAmount() == scrollBar.getMaximum()) {
setScrollToEnd(true);
} else {
setScrollToEnd(false);
}
});
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scrollPane.addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (future != null) {
future.cancel(false);
}
future = scheduler.schedule(() -> {
EventQueue.invokeLater(() -> {
System.out.println("Yes");
JViewport viewport = scrollPane.getViewport();
Point p = viewport.getViewPosition();
Dimension extentSize = viewport.getExtentSize();
//p.translate(extentSize.width, extentSize.height);
int rowIndex = rowAtPoint(p);
if (rowIndex >= 0) {
lastValue = getValueAt(rowIndex, 0);
}
});
}, 500, TimeUnit.MILLISECONDS);
}
});
scrollBar.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
//System.out.println(e);
}
@Override
public void mousePressed(MouseEvent e) {
//System.out.println(e);
lastValue = null;
}
@Override
public void mouseReleased(MouseEvent e) {
//System.out.println(e);
JViewport viewport = scrollPane.getViewport();
Point p = viewport.getViewPosition();
Dimension extentSize = viewport.getExtentSize();
//p.translate(extentSize.width, extentSize.height);
int rowIndex = rowAtPoint(p);
if (rowIndex >= 0) {
lastValue = getValueAt(rowIndex, 0);
}
}
@Override
public void mouseEntered(MouseEvent e) {
//System.out.println(e);
}
@Override
public void mouseExited(MouseEvent e) {
//System.out.println(e);
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
//System.out.println(e);
}
@Override
public void mouseDragged(MouseEvent e) {
// System.out.println(e);
}
@Override
public void mouseMoved(MouseEvent e) {
//System.out.println(e);
}
});
getTableModel().addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (lastValue != null && !autoScroll) {
int rowCount = getRowCount();
int newIndex = -1;
for (int i = 0; i < rowCount; i++) {
Object indexValue = getValueAt(i, 0);
if (indexValue == lastValue) {
newIndex = i;
break;
}
}
System.out.println(lastValue + " " + newIndex);
if (newIndex > 1) {
scrollRectToVisible(getCellRect(newIndex - 1, 0, true));
} else {
lastValue = null;
}
}
}
});
}
return scrollPane;
}
static int counter;
public static void main(String[] args) {
GuiTester.test(f -> {
JPanel panel = new JPanel(new BorderLayout());
MyTable table = new MyTable(50);
MyTableModel model = table.getTableModel();
Random random = new Random();
Timer timer = new Timer(100, e -> {
Data data = new Data();
data.setName(++counter + "");
data.setX(random.nextInt());
data.setY(random.nextInt());
data.setZ(random.nextInt());
data.setFlag(random.nextBoolean());
model.addRow(data.toObjectArray());
});
timer.start();
DataPanel dataPanel = new DataPanel();
table.getSelectionModel().addListSelectionListener(e -> {
int index = e.getFirstIndex();
if (index >= 0) {
Data data = (Data) table.getValueAt(index, 5);
dataPanel.setData(data);
}
});
JCheckBox checkBox = new JCheckBox("Scroll To End");
table.setScrollToEndListener(flag -> {
checkBox.setSelected(flag);
});
checkBox.addItemListener(e -> {
table.setScrollToEnd(checkBox.isSelected());
});
panel.add(checkBox, BorderLayout.NORTH);
panel.add(table.wrap(), BorderLayout.CENTER);
panel.add(dataPanel.getPanel(), BorderLayout.EAST);
return panel;
});
}
}
表模型
package org.example.table;
import javax.swing.table.DefaultTableModel;
public class MyTableModel extends DefaultTableModel {
private int max = -1;
public MyTableModel() {
this(-1);
}
public MyTableModel(int max) {
super(new Object[]{
"Name", "Flag", "X", "Y", "Z", "Data"
}, 0);
this.max = max;
}
@Override
public void addRow(Object[] rowData) {
if (getRowCount() == max) {
super.removeRow(0);
}
super.addRow(rowData);
}
}
虚拟数据
package org.example.table;
public class Data {
private String name;
private boolean flag;
private int x;
private int y;
private int z;
public Object[] toObjectArray() {
Object[] array = new Object[6];
array[0] = name;
array[1] = flag;
array[2] = x;
array[3] = y;
array[4] = z;
array[5] = this;
return array;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
}
datpanel是一个虚拟intellij窗体:
package org.example.table;
import javax.swing.*;
public class DataPanel {
private JTextField fieldName;
private JCheckBox flagCheckBox;
private JTextField fieldX;
private JTextField fieldY;
private JTextField fieldZ;
private JPanel panel;
public JPanel getPanel() {
return panel;
}
public void setData(Data data) {
fieldName.setText(data.getName());
fieldX.setText(data.getX() + "");
fieldY.setText(data.getY() + "");
fieldZ.setText(data.getZ() + " ");
flagCheckBox.setSelected(data.isFlag());
}
}
编辑:
我已经添加了鼠标和鼠标滚轮侦听器,并找到了第一个可见的行。并将滚动模式更改为simple或backingstore。
scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
那样的话,我有更好的功能。我仍然对更好的方法持开放态度。
暂无答案!
目前还没有任何答案,快来回答吧!