When I call JTable#scrollRectToVisible
, the row I want to show is hidden underneath the header in certain situations.
The rest of this question only makes sense when using the following code. This is a very simply program which I use to illustrate the problem. It shows a UI containing a JSplitPane
with in the upper part some control buttons, and the lower part contains a JTable
wrapped in a JScrollPane
(see screenshots at the bottom of this post).
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
public class DividerTest {
private final JSplitPane fSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
private final JTable fTable;
private final JScrollPane fScrollPane;
private boolean fHideTable = false;
public DividerTest() {
fTable = new JTable( createTableModel(50));
fScrollPane = new JScrollPane(fTable);
fSplitPane.setBottomComponent(fScrollPane);
fSplitPane.setTopComponent(createControlsPanel());
fSplitPane.setDividerLocation(0.5);
}
private JPanel createControlsPanel(){
JPanel result = new JPanel();
result.setLayout(new BoxLayout(result, BoxLayout.PAGE_AXIS));
final JCheckBox checkBox = new JCheckBox("Make table invisible before adjusting divider");
checkBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
fHideTable = checkBox.isSelected();
}
});
result.add(checkBox);
JButton upperRow = new JButton("Select row 10");
upperRow.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectRowInTableAndScroll(10);
}
});
result.add(upperRow);
JButton lowerRow = new JButton("Select row 45");
lowerRow.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectRowInTableAndScroll(45);
}
});
result.add(lowerRow);
JButton hideBottom = new JButton("Hide bottom");
hideBottom.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (fHideTable) {
fScrollPane.setVisible(false);
}
fSplitPane.setDividerLocation(1.0);
}
});
result.add(hideBottom);
JButton showBottom = new JButton("Show bottom");
showBottom.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fScrollPane.setVisible(true);
fSplitPane.setDividerLocation(0.5);
}
});
result.add(showBottom);
return result;
}
private void selectRowInTableAndScroll( int aRowIndex ){
fTable.clearSelection();
fTable.getSelectionModel().addSelectionInterval(aRowIndex, aRowIndex);
fTable.scrollRectToVisible(fTable.getCellRect(aRowIndex, 0, true));
}
public JComponent getUI(){
return fSplitPane;
}
private TableModel createTableModel(int aNumberOfRows){
Object[][] data = new Object[aNumberOfRows][1];
for( int i = 0; i < aNumberOfRows; i++ ){
data[i] = new String[]{"Row" + i};
}
return new DefaultTableModel(data, new String[]{"Column"});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Test frame");
frame.getContentPane().add(new DividerTest().getUI());
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
});
}
}
Unwanted behavior
- Run the above code
- Press the "Select row 10": row 10 is selected and visible
- Press the "Select row 45": row 45 is selected and visible
- Click the "Hide bottom" button. This will adjust the divider of the
JSplitPane
so that only the upper panel is visible - Click the "Select row 10" button. You see of course nothing because the table is not yet visible
- Click the "Show bottom" button. The divider is adjusted, but row 10 is hidden underneath the header. I expected it to be visible without needing to scroll.
Wanted behavior
Repeat the steps from above, but make sure the "Make table invisible before adjusting divider" checkbox is selected. This will call setVisible(false)
on the JScrollPane
around the JTable
before hiding the bottom panel.
By doing this, in the last step row 10 will be visible as the top most row, which is what I want. I just do not want to turn the scrollpane invisible: in my real application, the divider is adjusted in an animated way and as such you want to keep the table visible during the animation.
Screenshots
Unwanted: row 10 is invisible after performing the aforementioned steps
Wanted: row 10 is visible after performing the aforementioned steps
Environment
I do not think it will matter, but just in case: I am using JDK7 on a Linux system.