JTable#repaint() not functioning as expected [closed]

回眸只為那壹抹淺笑 提交于 2020-01-07 05:10:49

问题


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.

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.

Table Model

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) {
    }
}

Observer Class

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();
         }
     }
}

Main Class

    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();
    }

Add Record Button

    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:


  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.

  2. Also consider alternate implementations of the observer pattern mentioned here.

  3. 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);
    }
    
  4. 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.

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."



来源:https://stackoverflow.com/questions/13661821/jtablerepaint-not-functioning-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!