JTable#repaint()无法按预期运行 [英] JTable#repaint() not functioning as expected

查看:86
本文介绍了JTable#repaint()无法按预期运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此应用程序从文本文件中提取数据,并将其插入到JTable中.附加了Observer,每300毫秒检查一次文件是否更改,然后重新加载数据.我的Observer类中有setChanged()notifyObservers().

This application pulls data from a text file and inserts it into JTable. An Observer is attached to check every 300 ms if there is a change to the file and reload the data. I have the setChanged() and notifyObservers() in my Observer class.

将数据添加到表中时,getRowCount()报告已添加该行,通知程序可用.除了repaint()以外,几乎所有东西都在工作.我已经尝试了revalidate()fireTableDataChanged()都无济于事.我希望在此方面有所帮助.在整个过程中均未报告编译错误.

When data is added to the table, a getRowCount() reports that the row was added, notifiers are operational. Virtually everything is working except for the repaint(). I have tried revalidate() and fireTableDataChanged() all to no avail. I would appreciate some help on this. No compile errors are reported throughout the process.

表模型

package HardwareDbFile;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;

public class HardwareFileTableModel extends AbstractTableModel{
    protected Vector data;
    protected Vector columnNames ;
    protected String datafile;

    public HardwareFileTableModel(String file){
        datafile = file;
        initVectors();  
    }

    public void initVectors() {
        String aLine ;
        data = new Vector();
        columnNames = new Vector();
        try {
            FileInputStream fin =  new FileInputStream(datafile);
            try (BufferedReader br = new BufferedReader(new InputStreamReader(fin))) {
                StringTokenizer st1 = new StringTokenizer(br.readLine(), "|");
                while(st1.hasMoreTokens()) {
                    columnNames.addElement(st1.nextToken());
                }
                // extract data
                while ((aLine = br.readLine()) != null) {
                    StringTokenizer st2 = new StringTokenizer(aLine, "|");
                    while(st2.hasMoreTokens()) {
                        data.addElement(st2.nextToken());
                    }
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public int getRowCount() {
        return data.size() / getColumnCount();
    }

    @Override
    public int getColumnCount(){
        return columnNames.size();
    }

    @Override
    public String getColumnName(int columnIndex) {
        String colName = "";

        if (columnIndex <= getColumnCount()) {
            colName = (String)columnNames.elementAt(columnIndex);
        }
        return colName;
    }

    @Override
    public Class getColumnClass(int columnIndex){
        return String.class;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
    }


    public Object getValueAt(int rowIndex, int columnIndex) {
        return (String)data.elementAt( (rowIndex * getColumnCount()) + columnIndex);
    }


    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    }
}

观察者类

package HardwareDbFile;

import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.Timer;

 public class HardwareFileObserver extends Observable implements ActionListener {
     Timer time = new Timer(300,this); // check every 300ms
     long lastModified;
     String file ;

     HardwareFileObserver (String string) {
         file = string;
         File f = new File(file);
         lastModified = f.lastModified(); // original timestamp
         time.start();
     }

     @Override
     public void actionPerformed(ActionEvent e) {
         File f = new File(file);
         long actualLastModified = f.lastModified();
         if (lastModified != actualLastModified) {
             // the file have changed
             lastModified = actualLastModified;
             setChanged();
             notifyObservers();
         }
     }
}

主类

    public class HardwareInventoryUI extends javax.swing.JFrame implements Observer {

    private String datafile = "hardware.dat";
    private String dataFilePath = "C:\\Windows\\Temp\\hardware.dat";
    protected HardwareFileTableModel model;

    /**
     * Creates new form HardwareInventoryUI
     */
    public HardwareInventoryUI() {
        initComponents();

        model = new HardwareFileTableModel(dataFilePath);
        HardwareFileObserver  fileWD;

        // this Observable object is monitoring any file change
        fileWD = new HardwareFileObserver(dataFilePath);
        fileWD.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        // reload data because data file have changed
        model.initVectors();
        jTable.repaint();
    }

添加记录按钮

    private void jAddRecordActionPerformed(java.awt.event.ActionEvent evt) {                                           

        String toolID = jToolID.getText();
        String toolName = jToolName.getText();
        String quantity = jQuantity.getText();
        String itemPrice = jItemPrice.getText();
        try {
            model = new HardwareFileTableModel(dataFilePath);
            FileWriter fstream = new FileWriter(dataFilePath, true);
            try (BufferedWriter newRecord = new BufferedWriter(fstream)) {
                newRecord.newLine();
                newRecord.write(toolID + "|"+ toolName + "|" + quantity + "|" + itemPrice );
            }
        } catch (IOException ex) {
            Logger.getLogger(HardwareInventoryUI.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

推荐答案

  1. 您的TableModel应该实现Observer,而不是您的视图.在update()方法中,更新datafireTableDataChanged(). JTable侦听其TableModel并作为响应自动更新.

  1. Your TableModel should implement Observer, not your view. In the update() method, update data and fireTableDataChanged(). A JTable listens to its TableModel and updates itself automatically in response.

还考虑在此处提到的观察者模式的替代实现.

Also consider alternate implementations of the observer pattern mentioned here.

此处所示,您对setValueAt()的实现不正确.您需要触发将通知监听表更改的事件:

As illustrated here, your implementation of setValueAt() is incorrect. You need to fire the event that would notify the listening table of the change:

@Override
public void setValueAt(Object value, int row, int column) {
    // update data
    fireTableCellUpdated(row, column);
}

  • 如果可以将datafile的内容作为命令的标准输出获得,则可以使用

  • If the content of your datafile can be obtained as the standard output of a command, you may be able to eliminate the file using the approach outlined here.

    附录:正如@kleopatra所评论的那样,请注意,使用行为良好的模型,您无需考虑任何视图更新,它们会自动神奇地发生:-)或反之:如果手动重新绘制视图(例如表,树,列表)似乎是一种解决方案,模型实现不正确."

    Addendum: As @kleopatra comments, "Note that with a well-behaved model, you never need to put any thought into view updates, they simply happen auto-magically :-) Or the other way round: if manual repaints on a view (such as table, tree, list) seem be be a solution, the model implementation is incorrect."

    这篇关于JTable#repaint()无法按预期运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆