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;

    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()) {
                // extract data
                while ((aLine = br.readLine()) != null) {
                    StringTokenizer st2 = new StringTokenizer(aLine, "|");
                    while(st2.hasMoreTokens()) {
        catch (Exception e) {
    public int getRowCount() {
        return data.size() / getColumnCount();

    public int getColumnCount(){
        return columnNames.size();

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

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

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

    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

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

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

        model = new HardwareFileTableModel(dataFilePath);
        HardwareFileObserver  fileWD;

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

    public void update(Observable o, Object arg) {
        // reload data because data file have changed

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.write(toolID + "|"+ toolName + "|" + quantity + "|" + itemPrice );
        } catch (IOException ex) {
            Logger.getLogger(HardwareInventoryUI.class.getName()).log(Level.SEVERE, null, ex);



  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:

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