【问题标题】:Jtable doesn't refresh/update dataJtable 不刷新/更新数据
【发布时间】:2012-09-28 19:32:57
【问题描述】:

JTable/JScrollPane 有问题。我的数据表没有刷新/更新。我正在使用DefultTableModel,根据代码一切都很好,我没有任何错误。另外我有一个带有分页的表格,这就是为什么我使用动作监听器和按钮“prev”和“next”。我正在从其他函数传递到在 JTable 的类中编码的函数。问题是我填充了包含表格数据的数组,但表格不会更新/刷新它。这是我的代码。提前谢谢。

BIG EDIT 旧代码已被删除。我添加了新代码,可以帮助你们了解我遇到的问题。希望这会有所帮助。问候。

首先是显示 gui 的类:

import javax.swing.*;
public class Glavni {
public static void main(String[] args)  {
    // TODO Auto-generated method stub
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
                gui Scanner = new gui();
                Scanner.setVisible(true);
        }
    });
}

}

第二个是将String传递给包含jtable的gui类的类

public class passDatatoTable {
public void passData(){
    String str1,str2,str3,str4;
    gui SendStringsToGUI = new gui();
    for (int i =0;i<=10;i++){
            str1="Column 1 of row: "+i;
            str2="Column 2 of row: "+i;
            str3="Column 3 of row: "+i;
            str4="Column 4 of row: "+i;
            SendStringsToGUI.WriteMonitorData(str1, str2, str3, str4);

    }
  }
}

接下来是gui(constructor)的声明:

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class gui extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
 String[][] data = new String[100][4];

 String[] columnNames = new String[]{
         "IP", "PC_NAME", "ttl", "db"
 };
 DefaultTableModel model = new DefaultTableModel(data,columnNames);


    JTable table =  new JTable(model);
    JScrollPane scrollPane = new JScrollPane(table);
    int i=0;
public void WriteMonitorData (String IP, String PC_NAME, String ttl, String gw)
{
    System.out.println(IP);//just for testing (check if data was passed)
    model.setValueAt(IP, i, 0);
    model.setValueAt(PC_NAME, i, 1);
    model.setValueAt(ttl, i, 2);
    model.setValueAt(gw, i, 3);

    i++;
    model.fireTableDataChanged();
    table.repaint();
    scrollPane.repaint();

}   
gui(){

JButton addData= new JButton("Add Data");
JButton next = new JButton("next");
JButton prev = new JButton("prev");
addData.addActionListener(this);
next.addActionListener(this);
prev.addActionListener(this);
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.add(addData);
buttonPanel.add(prev);
buttonPanel.add(next);
panel.add(buttonPanel, BorderLayout.SOUTH);
panel.add(table.getTableHeader(), BorderLayout.PAGE_START);
panel.add(scrollPane, BorderLayout.CENTER);
getContentPane().add(panel);
}

这里是 actionListener:

public void actionPerformed(ActionEvent e) {
if ("Add Data".equals(e.getActionCommand())){

        passDatatoTable passSomeData = new passDatatoTable();
        passSomeData.passData();
              }
 if ("next".equals(e.getActionCommand())) {
         Rectangle rect = scrollPane.getVisibleRect();
         JScrollBar  bar = scrollPane.getVerticalScrollBar();
         int blockIncr = scrollPane.getViewport().getViewRect().height;
             bar.setValue(bar.getValue() + blockIncr);
             scrollPane.scrollRectToVisible(rect);
     }
     if ("prev".equals(e.getActionCommand())) {
         Rectangle rect = scrollPane.getVisibleRect();
         JScrollBar  bar = scrollPane.getVerticalScrollBar();
         int blockIncr = scrollPane.getViewport().getViewRect().height;
             bar.setValue(bar.getValue() - blockIncr);
             scrollPane.scrollRectToVisible(rect);
     }

  }

【问题讨论】:

  • a) 请学习 java 命名约定并遵守它们。 b) 永远不要在模型之外调用任何 fireXX 方法(模型必须自己处理) c) 永远不要调用 repaint(这不是必需的)

标签: java swing jtable jscrollpane defaulttablemodel


【解决方案1】:

你的第一个 sn-p 显示了这个:

JTable table = new JTable(model);

但您的 gui() 构造函数显示:

JTable table = new JTable(data, columnNames);

您启动表两次。一次使用TableModel (JTable(TableModel tm)) 下一次使用JTable(int rows,int cols) 这不好,在构造函数中启动一次JTable:

gui() {
DefaultTableModel model = new DefaultTableModel(data,columnNames);
JTable table =  new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);

JButton next = new JButton("next");
JButton prev = new JButton("prev");
next.addActionListener(this);
prev.addActionListener(this);
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.add(prev);
buttonPanel.add(next);
panel.add(buttonPanel, BorderLayout.SOUTH);
panel.add(table.getTableHeader(), BorderLayout.PAGE_START);
panel.add(scrollPane, BorderLayout.CENTER);
getContentPane().add(panel);
}

更新:

这是一个示例,其中有一个线程将在 UI 可见后 2.5 秒启动并更改 JTable 的值:

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class Test extends JFrame {

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Test().createAndShowUI();
            }
        });

    }

    private void createAndShowUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        initComponents(frame);
        frame.pack();
        frame.setVisible(true);
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(2500);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                } 
                SwingUtilities.invokeLater(new Runnable() {

                     @Override
                     public void run() {
                       model.setValueAt("hello", 0, 0);
                     }
                });
            }
        }).start();
    }
    static DefaultTableModel model;

    private void initComponents(JFrame frame) {

        String data[][] = {
            {"1", "2", "3"},
            {"4", "5", "6"},
            {"7", "8", "9"},
            {"10", "11", "12"}
        };

        String col[] = {"Col 1", "Col 2", "Col 3"};

        model = new DefaultTableModel(data, col);
        JTable table = new JTable(model);

        frame.getContentPane().add(new JScrollPane(table));
    }
}

【讨论】:

  • 你在这里犯了和你之前的代码 sn-p 一样的错误。您在另一个线程上更新 Swing 组件,然后是 EDT(通过更改可运行文件中的表模型)。请调整这个
  • 要么你使用SwingUtilities(你已经在你的main方法中使用过,所以你应该熟悉它——除非你只是在不知道它意味着什么的情况下从某个地方复制粘贴了该代码),或者您放弃 Thread 并用 javax.swing.Timer 替换它,该 javax.swing.Timer 旨在以固定间隔在 EDT 上执行操作
  • 现在你在 EDT 上睡觉,这基本上会让你的 UI 没有响应。我对SwingUtilities 调用的建议不是针对整个Runnable,只是针对更新模型部分。我强烈建议您阅读Swing concurrency tutorial
  • 我知道睡眠意味着什么。但是模拟数据加载或实际数据加载不应该在 EDT 上发生。并且对于具有大量支持的帖子(相对于其他 Swing 相关问题而言,高意味着),答案不应违反基本的 Swing 线程规则 imo。现在它已得到纠正,我可以删除我的反对票
  • -1 代表模型触发事件 - 这是模型本身的专有责任
【解决方案2】:

根据我从 cmets 和问题中了解到的情况,您首先通过在构造函数中将数据作为数组传递来创建了 DefaultTableModel

String[][] data = new String[100][4];
String[] columnNames = new String[]{
     "IP", "PC_NAME", "ttl", "db"};
DefaultTableModel model = new DefaultTableModel(data,columnNames);

然后您尝试通过调整这些数组来修改表格。这永远不会有任何影响,因为DefaultTableModel 不使用这些数组。这可以在该类的源代码中看到

public DefaultTableModel(Object[][] data, Object[] columnNames) {
    setDataVector(data, columnNames);
}

最终归结为

protected static Vector convertToVector(Object[][] anArray) {
    if (anArray == null) {
        return null;
    }
    Vector<Vector> v = new Vector<Vector>(anArray.length);
    for (Object[] o : anArray) {
        v.addElement(convertToVector(o));
    }
    return v;
}

所以数组的所有元素都被复制到一个内部Vector 中并且不再使用该数组。

解决方案:不要更新数组而是更新DefaultTableModel。该类提供了向其中添加/删除数据所需的所有 API。

【讨论】:

  • 谢谢罗宾。我将尝试实施您的建议和代码。非常感谢。
  • 嗨@Robin。再次感谢您的帮助。看看我更新的代码。有一个完整的代码被使用。您可以简单地在 Eclipse 中复制/粘贴它...正如您所见,我不再使用数组了。我正在使用 DefaultTableModel 函数 setValueAt() 用于向模型添加新值。仍然没有显示数据...
  • @ZhiZha 你的passDatatoTable 类仍然创建一个新的UI (gui SendStringsToGUI = new gui();) 而不是更新现有的
  • 感谢@Robin 更新。那么告诉我如何正确传递数据?我正在考虑使用 String 作为传递变量创建额外的构造函数,并从那里更新表并且不会创建新的 GUI。我将尝试对其进行编码并返回结果。
  • 我尝试将它与其他构造函数一起使用,但仍然无法正常工作。有人知道这方面的好教程吗?我正在处理这个 2 天,但仍然没有运气......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多