简体   繁体   English

Swing:在JTable结构发生变化后,JScrollPane不会刷新

[英]Swing : JScrollPane doesn't refresh after changes in the structure of a JTable

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. 当我使用下面的方法修改DefaultTableModel的结构时,JTable会刷新,但不会刷新JScrollPane。 I have to apply a second time this method to refresh the 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! 任何帮助非常感谢!

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. 这是一个测试程序,它显示当JScrollPane持有JTable并且通过setDataVector(...)更改DefaultTableModel的DataVector时,没有必要在模型上调用fireTableDataChanged()以使JTable的数据正确更改并且正确看待。

The program GUI looks like the images below. 程序GUI看起来像下面的图像。
Before Data Changed: 数据更改前:
在此输入图像描述

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 sscce similar (or simpler) than what I've posted above. 为了获得更多更好的帮助,OP必须创建与我上面发布的类似(或更简单)相似(或更简单)的sscce 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. 或者通过不使用SpringLayout来保存JTable来解决他的问题,而是将其直接添加到JScrollPane的视口视图中,或者使用JPanel将其添加到BorderLayout(注意也添加JTable的头部)并将其添加到JScrollPane的视口视图。

I've run into this problem before. 我之前遇到过这个问题。

Try invalidating the JTable and repainting the JScrollPane. 尝试使JTable无效并重新绘制JScrollPane。

table.invalidate();
scrollPane.repaint();

Try invoking revalidate() method on table. 尝试在表上调用revalidate()方法。 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. 根据JScrollPanel http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html#update - “动态更改客户端大小”的规范,此方法应通知滚动面板。

table.revalidate();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM