Ich habe eine JTable
, die Zeilen dynamisch vom Benutzer hinzugefügt haben können. Es sitzt in einem JScrollPane
, so wie die Anzahl der Zeilen groß genug wird, wird der Scroller aktiv. Mein Wunsch ist, dass wenn der Benutzer eine neue Zeile hinzufügt, der Scroller den ganzen Weg nach unten bewegt, so dass die neue Zeile in der Scroll-Palette sichtbar ist. Ich versuche derzeit (SSCCE), einen Listener für Tabellenmodelle zu verwenden, um zu erkennen, wann die Zeile eingefügt wurde, und zwinge die Bildlaufleiste ganz nach unten, wenn die Erkennung durchgeführt wird. Es scheint jedoch, dass diese Erkennung "zu früh" ist, da das Modell aktualisiert wurde, aber die neue Zeile wurde noch nicht gemalt, also was passiert, ist der Scroller bewegt sich ganz nach unten vor die neue Zeile eingefügt wird und dann wird die neue Zeile direkt unter dem Ende des Bereichs eingefügt (außerhalb der Sichtbarkeit).JTable Modell Listener erkennt eingefügte Zeilen zu früh (bevor sie gezeichnet werden)
Offensichtlich ist dieser Ansatz irgendwie falsch. Was ist der richtige Ansatz?
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class TableListenerTest {
private JFrame frame;
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel tableModel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TableListenerTest window = new TableListenerTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public TableListenerTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
JSplitPane splitPane = new JSplitPane();
frame.getContentPane().add(splitPane);
scrollPane = new JScrollPane();
scrollPane.setPreferredSize(new Dimension(100, 2));
splitPane.setLeftComponent(scrollPane);
tableModel = new DefaultTableModel(new Object[]{"Stuff"},0);
table = new JTable(tableModel);
scrollPane.setViewportView(table);
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.INSERT) {
JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
scrollBar.setValue(scrollBar.getMaximum());
}
}
});
JButton btnAddRow = new JButton("Add Row");
btnAddRow.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
tableModel.addRow(new Object[]{"new row"});
}
});
splitPane.setRightComponent(btnAddRow);
}
}
BEARBEITEN: Aktualisiert SSCCE unten basierend auf der Anfrage von trashgod. Diese Version funktioniert jedoch immer noch nicht, wenn ich die Bildlauflogik vom Tabellenmodell-Listener zum Button-Listener verschiebe, dann funktioniert es!
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class TableListenerTest {
private JFrame frame;
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel tableModel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TableListenerTest window = new TableListenerTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public TableListenerTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
JSplitPane splitPane = new JSplitPane();
frame.getContentPane().add(splitPane);
scrollPane = new JScrollPane();
scrollPane.setPreferredSize(new Dimension(100, 2));
splitPane.setLeftComponent(scrollPane);
tableModel = new DefaultTableModel(new Object[]{"Stuff"},0);
table = new JTable(tableModel);
scrollPane.setViewportView(table);
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.INSERT) {
int last = table.getModel().getRowCount() - 1;
Rectangle r = table.getCellRect(last, 0, true);
table.scrollRectToVisible(r);
}
}
});
JButton btnAddRow = new JButton("Add Row");
btnAddRow.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
tableModel.addRow(new Object[]{"new row"});
}
});
splitPane.setRightComponent(btnAddRow);
}
}
Danke, aber es scheint nicht direkt mein Problem zu lösen, das macht mich fragen, ob es nicht möglich ist? In Ihrem Beispiel überprüfen Sie ständig einmal pro Sekunde, ob Sie bis zum Ende scrollen sollen oder nicht.Das möchte ich jedoch, sobald "Zeile hinzufügen" angeklickt wird. Wenn ich auf den Knopf einen Haufen in deiner App klicke, erleidet er das gleiche Problem wie mein (aber "repariert" sich selbst in weniger als 1 Sekunde). Ist es unmöglich, das Scrollen zu ermöglichen, sobald der Benutzer auf die Schaltfläche klickt, weil das Modell und die GUI sich auf separaten Threads befinden, die ich vermute? – The111
Ich sollte hinzufügen, dass ich 'scrollRectToVisible' in meinem SSCCE versuchte und es immer noch das gleiche Problem aufweist, das vielleicht relevanter ist als das, was ich gerade oben geschrieben habe. – The111
Ich habe oben ausgearbeitet; Bitte aktualisieren Sie Ihre Frage mit Ihrem aktuellen Code. – trashgod