Когда я вызываю JTable#scrollRectToVisible
, строка, которую я хочу показать, скрыта под заголовком в определенных ситуациях.JTable # scrollRectToVisible в сочетании с JSplitPlane показывает неправильную строку
Остальная часть этого вопроса имеет смысл только при использовании следующего кода. Это очень простая программа, которую я использую для иллюстрации проблемы. Он показывает интерфейс, содержащий JSplitPane
, а в верхней части - некоторые кнопки управления, а нижняя часть содержит JTable
, завернутый в JScrollPane
(см. Скриншоты в нижней части этой публикации).
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);
}
});
}
}
Нежелательное поведение
- Выполнить код выше
- Нажмите "Выбрать строку 10": строка 10 выбран и видимый
- Нажмите "Выбрать строку 45": строка 45 выбирается и отображается
- Нажмите кнопку «Скрыть нижний». Это отрегулирует делитель
JSplitPane
так, чтобы видна только верхняя панель. - Нажмите кнопку «Выбрать строку 10». Вы, конечно, ничего не видите, потому что таблица еще не виден
- Нажмите кнопку «Показать нижнюю». Делитель настроен, но строка 10 скрыта под заголовком. Я ожидал, что он будет виден без необходимости прокрутки.
Wanted поведения
Повторите шаги с выше, но убедитесь, что установлен флажок «Сделать таблицу невидимой перед настройкой делителя». Это вызовет setVisible(false)
на JScrollPane
вокруг JTable
, прежде чем спрятать нижнюю панель.
Делая это, в последнем шаге строка 10 будет видна как самая верхняя строка, что я и хочу. Я просто не хочу превращать scrollpane в невидимое: в моем реальном приложении делитель настраивается анимированным способом и, как таковой, вы хотите, чтобы таблица отображалась во время анимации.
Скриншоты
Нежелательные: строка 10 является невидимым после выполнения вышеуказанных шагов
Требуются: строка 10 видна после выполнения вышеуказанных шагов
Environment
Я не думаю, что это будет иметь значение, но на всякий случай: я использую JDK7 на системе Linux.
пожалуйста, Что выход, используя [Прямоугольник из JVievport и вместе с JTables row] (http://stackoverflow.com/a/7052751/714968), потому что игнорирует кеш красок, и что возвращает значение из Rectangle.contains(), потому что это может быть картина артефакта, так как в стороне разделитель должен быть завернутый в invokeLater во всех случаях (анимация, такая же, как требуется для анимации с/в JTree) – mKorbel