Java Swing:在 JTable 的结构发生变化后,JScrollPane 不会刷新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9706682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swing : JScrollPane doesn't refresh after changes in the structure of a JTable
提问by Bastien_
I have a JTable, associated with a DefaultTableModel, in a JPanel with a SpringLayout which is in a JScrollPane.
我有一个 JTable,与 DefaultTableModel 关联,在 JPanel 中,SpringLayout 位于 JScrollPane 中。
When I modify the structure of the DefaultTableModel with the method below the JTable is refreshed but not the JScrollPane. I have to apply a second time this method to refresh the JScrollPane.
当我使用下面的方法修改 DefaultTableModel 的结构时,会刷新 JTable,但不会刷新 JScrollPane。我必须再次应用此方法来刷新 JScrollPane。
public void updateProjectView() {
SwingProjectViewerController spvc = SwingProjectViewerController.
getInstance();
this.projectTitle.setText(spvc.getAcronym() + " : " + spvc.getTitle());
Object[][] tableContent =
spvc.getCriteria(CriteriaPreselectionController.getInstance().
getCriteriaPreselection());
Object[] columnsName = new Object[]{"Col1", "Col2"};
this.tableModel.setDataVector(tableContent, columnsName);
this.tableModel.fireTableStructureChanged();
}
Any help much appreciated!
非常感谢任何帮助!
采纳答案by Hovercraft Full Of Eels
Here is a test program that shows that when a JTable is held by a JScrollPane and the DefaultTableModel's DataVector is changed via setDataVector(...)
it is not necessary to call fireTableDataChanged()
on the model for the JTable's data to change correctly and be viewed correctly.
这是一个测试程序,它表明当 JTable 由 JScrollPane 持有并且 DefaultTableModel 的 DataVector 通过更改时,setDataVector(...)
不需要调用 fireTableDataChanged()
模型以使 JTable 的数据正确更改并正确查看。
The program GUI looks like the images below.
Before Data Changed:
程序 GUI 如下图所示。
数据改变前:
After Data Changed:
数据更改后:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
@SuppressWarnings("serial")
public class ScrollPaneRefresh extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 200;
private Integer[][] initialData = {
{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0},
{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0},
{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}
};
private Integer[][] newData = {
{1, 2}, {3, 4}
};
private String[] columnNames = {"Col1", "Col2"};
private TablePanel gregsPanel = new TablePanel("With fireTableDataChanged", initialData, columnNames);
private TablePanel myPanel = new TablePanel("Without fireTableDataChanged", initialData, columnNames);
public ScrollPaneRefresh() {
gregsPanel.setButtonAction(new AbstractAction("Change Table Data") {
private boolean changeToNewData = true;
@Override
public void actionPerformed(ActionEvent evt) {
if (changeToNewData) {
gregsPanel.setTableModelDataVector(newData, columnNames);
} else {
gregsPanel.setTableModelDataVector(initialData, columnNames);
}
gregsPanel.fireTableDataChanged();
changeToNewData = !changeToNewData;
}
});
myPanel.setButtonAction(new AbstractAction("Change Table Data") {
private boolean changeToNewData = true;
@Override
public void actionPerformed(ActionEvent evt) {
if (changeToNewData) {
myPanel.setTableModelDataVector(newData, columnNames);
} else {
myPanel.setTableModelDataVector(initialData, columnNames);
}
// myPanel.getScrollPane().getViewport().revalidate();
changeToNewData = !changeToNewData;
}
});
setLayout(new GridLayout(1, 0));
add(gregsPanel.getMainPanel());
add(myPanel.getMainPanel());
}
@Override // so scrollbars will show
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ScrollPaneRefresh mainPanel = new ScrollPaneRefresh();
JFrame frame = new JFrame("ScrollPaneRefresh");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class TablePanel {
private JPanel mainPanel = new JPanel();
private DefaultTableModel dm;
private JTable table = new JTable();
private JButton changeTableBtn = new JButton();
private JScrollPane scrollpane = new JScrollPane(table);
public TablePanel(String title, Object[][] data, Object[] columnNames) {
dm = new DefaultTableModel(data, columnNames);
table.setModel(dm);
JPanel btnPanel = new JPanel();
btnPanel.add(changeTableBtn);
mainPanel.setBorder(BorderFactory.createTitledBorder(title));
mainPanel.setLayout(new BorderLayout(5, 5));
mainPanel.add(scrollpane, BorderLayout.CENTER);
mainPanel.add(btnPanel, BorderLayout.PAGE_END);
}
public void setButtonAction(Action action) {
changeTableBtn.setAction(action);
}
public void setTableModelDataVector(Object[][] data, Object[] columnNames) {
dm.setDataVector(data, columnNames);
}
public void fireTableDataChanged() {
dm.fireTableDataChanged();
}
public JScrollPane getScrollPane() {
return scrollpane;
}
public JComponent getMainPanel() {
return mainPanel;
}
}
The deficiency of my example above is that it does not reproduce the original poster's problem, and I think that is due to us use of SpringLayout, which he does not fully describe or show code:
我上面的例子的不足是没有重现原发帖人的问题,我认为是由于我们使用了SpringLayout,他没有完整描述或展示代码:
I have a JTable, associated with a DefaultTableModel, in a JPanel with a SpringLayout which is in a JScrollPane.
我有一个 JTable,与 DefaultTableModel 关联,在 JPanel 中,SpringLayout 位于 JScrollPane 中。
For more and better help, the OP is going to have to create his own ssccesimilar (or simpler) than what I've posted above. Either that, or solve his problem by not using SpringLayout to hold the JTable but rather either add it directly to the JScrollPane's viewport view or add it to a BorderLayout using JPanel (taking care to also add the JTable's header) and add that to the JScrollPane's viewport view.
为了获得更多更好的帮助,OP 将不得不创建自己的sscce,与我上面发布的内容类似(或更简单)。要么,要么通过不使用 SpringLayout 来保存 JTable 来解决他的问题,而是将其直接添加到 JScrollPane 的视口视图或使用 JPanel 将其添加到 BorderLayout(注意还添加 JTable 的标题)并将其添加到 JScrollPane 的视口视图。
回答by Gilbert Le Blanc
I've run into this problem before.
我以前遇到过这个问题。
Try invalidating the JTable and repainting the JScrollPane.
尝试使 JTable 无效并重新绘制 JScrollPane。
table.invalidate();
scrollPane.repaint();
回答by npenkov
Try invoking revalidate() method on table. According to specification of JScrollPanel http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html#update- "Dynamically changing client size" this method should notify Scroll Panel.
尝试在表上调用 revalidate() 方法。根据 JScrollPanel http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html#update- “动态更改客户端大小”的规范,此方法应通知滚动面板。
table.revalidate();