Ho un JTable
che può avere le righe aggiunte dinamicamente dall'utente. Si trova in un JScrollPane
, così come il numero di righe diventa abbastanza grande, lo scroller diventa attivo. Il mio desiderio è che quando l'utente aggiunge una nuova riga, lo scroller si sposta completamente verso il basso, in modo che la nuova riga sia visibile nello scorrimento. Sono al momento (SSCCE sotto) cercando di utilizzare un listener di modelli di tabelle per rilevare quando viene inserita la riga e forzare la barra di scorrimento fino in fondo quando viene effettuato il rilevamento. Tuttavia, sembra che questa rilevazione sia "troppo presto", poiché il modello è stato aggiornato ma la nuova riga non è ancora stata dipinta, quindi ciò che accade è lo scroller che si sposta fino in fondo solo prima dello la nuova riga è inserita , e quindi la nuova riga viene inserita appena sotto la fine del riquadro (non visibile).Il listener del modello JTable rileva le righe inserite troppo presto (prima che vengano disegnate)
Ovviamente questo approccio è sbagliato in qualche modo. Qual è l'approccio corretto?
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);
}
}
EDIT: Aggiornato SSCCE di seguito in base alla richiesta di trashgod. Questa versione continua a non funzionare, tuttavia, se sposto la logica di scorrimento dal listener del modello di tabella al listener di pulsanti come ha fatto, allora funziona!
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);
}
}
Grazie, ma non sembra per risolvere direttamente il problema, che mi fa chiedere se è impossibile? Nel tuo esempio stai controllando costantemente una volta al secondo se devi o meno scorrere fino alla fine.Tuttavia, voglio che ciò accada non appena si fa clic su "aggiungi riga". Se faccio clic sul pulsante di un gruppo nella tua app, subisce lo stesso problema che fa il mio (ma "risolve" se stesso in meno di 1 secondo). E 'impossibile che lo scrolling avvenga non appena l'utente fa clic sul pulsante, perché il modello e la GUI sono su thread separati. Sto indovinando? – The111
Dovrei aggiungere che ho provato 'scrollRectToVisible' nel mio SSCCE e presenta ancora lo stesso problema, che è forse più rilevante di quello che ho appena scritto sopra. – The111
Ho elaborato sopra; per favore aggiorna la tua domanda con il tuo codice attuale. – trashgod