This program is one part of the GUI part for my reminder program.
I would like to update the JTable which shows all the task and will refresh every 2 second.
I have questions...
(1)the SwingWorker never executes( I put println in the code but it shows nothing )
How to make it work?
(2) If I remove SwingWorker, but I have the timer, there will be a lot of exceptions appear.. why?
(3) Is there a way to refresh everytime data(taskHashMap) change???

Thank you very much

package gui;

import java.awt.Component;
import java.util.ArrayList;
import java.util.Vector;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

import Storage.Task;
import Storage.TaskHashMap;

public class AutoUpdateJTable {
    private JTable jTable;
    private DefaultTableModel model;
    private Vector<String> listLabel = new Vector<String>();

    AutoUpdateJTable(final JTable jTable){
        this.jTable = jTable;
        model = (DefaultTableModel) this.jTable.getModel();
        SwingWorker<JTable, Void> worker = new SwingWorker<JTable, Void>() {

            @Override
            protected JTable doInBackground() throws Exception {
                // TODO Auto-generated method stub
                System.out.println("enter swing");
                Timer timer = new Timer(2000, new ActionListener(){

                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        // TODO Auto-generated method stub
                        //updateJTable();
                        makeJLabel(new Task());
                        setAppearance();
                        System.out.println(listLabel.get(0).toString());
                    }

                });
                timer.start();
                timer.setRepeats(true);
                return null;
            }
        };
    }

    private void setAppearance() {
        jTable.setRowHeight(30);
        while(model.getRowCount()>0)
            model.removeRow(0);
        jTable.getColumnModel().getColumn(0).setCellRenderer(new MyRenderer());
        model.addRow(listLabel);
        System.out.println(listLabel.toString());
    }


    private void makeJLabel(Task task) {
        task = new Task("test");

        String str;
        str =   "<HTML><b>" 
                + task.getName() + " " 
                //+ task.getDescription() + " "
                + "</HTML>";
        listLabel.add(str);

        System.out.println(listLabel.toString());
    }

    private void makeAllJLabel(TaskHashMap taskHashMap) {
        int length = 0;
        for(int i=0; i<length; i++) {
            makeJLabel(new Task());
        }
    }

    private void updateJTable() {
        //retrieve TaskHashMap
        listLabel = new Vector<String>();
        TaskHashMap taskHashMap = new TaskHashMap();
        makeAllJLabel(taskHashMap);
        setAppearance();
    }

    class MyRenderer extends DefaultTableCellRenderer {

          /*
           * @see TableCellRenderer#getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int)
           */
          public Component getTableCellRendererComponent(JTable table, Object value,
                                                         boolean isSelected, boolean hasFocus, 
                                                         int row, int column) {
            JLabel label = new JLabel(value.toString());
            return label;   
          }
    }

}

because you never use it. you create an instance of SwingWorker (worker) and define it's methods, but unless you actually call those methods, how did you expect to use it?

I couldn't see where you call excute() for your SwingWorker, which may explain why it doesn't execute.
In any case, all it seems to do is to start a swing Timer, so why bother? Just start the timer from your ordinary in-line code. If you get exceptions. post them so we can see what they are.
To see if there's a way to monitor the hashmap for changes, you'll need to post its code. In the worst case you can sub-class it, override its update methods to call the super implementations then call a Listener interface to notify changes.

Thank you very much.
How to execute the SwingWorker?

Here is the taskHashMap class. It is not completed yet. This part is supposed to be done by my friend soon.

package Storage;

import java.util.Map;
import java.util.Random;
import java.util.HashMap;
import java.util.Set;
public class TaskHashMap
{
    private Map<String,Task> taskList;
    /** constructor*/
    public TaskHashMap()
    {
        taskList=new HashMap<String,Task>();
    }
    /** Member function to add task
     * 
     * @param newTask task to be added
     */
    public boolean addTask(Task taskToBeAdded)
    {
        assert(taskToBeAdded!=null);
        taskToBeAdded.setTaskId(generateUniqueId(taskToBeAdded));
        taskList.put(taskToBeAdded.getTaskId(), taskToBeAdded);
        return true;
    }
    private String generateUniqueId(Task taskToBeAdded)
    {
        String taskId;
        Random random=new Random();
        taskId=taskToBeAdded.getEndDateTime().generateDateCode()+taskToBeAdded.getEndDateTime().generateTimeCode()+(char)(random.nextInt('Z'-'A'+1)+'A');
        return taskId;
    }
    /** Member function to delete task
     * 
     * @param taskId id of the task to be deleted
     */
    public void delete(Task taskToRemove)
    {
        assert(taskToRemove!=null);
        taskList.remove(taskToRemove.getTaskId());
    }
    /** Member function to get task
     * 
     * @param taskId id of the task needed
     * @return the task of the provided taskId
     */
    public Task getTaskbyId(String id)
    {
        return taskList.get(id);
    }
    public Set<String> getKeySet()
    {
        return taskList.keySet();
    }
}

If you really still want to execute the SwingWorker you have to call its execute() method, just like I implied in my previous post, and just like it says in the API doc. (But it really is redundant, and a waste of time.)
The best thing is to get your friend to add a ChangeListener capability to his class - write an addChangeListener(ChangeListener cl) method that stores the ChangeListener, then whenever he updates the data he calls the ChangeListener's stateChanged method. In yhour code you implement the stateChanged method, and call his addChangeListener(this). Now whenever the data changes your stateChanged method will be called. It's exactly the same pattern that Swing uses throughout.

Thank you very much. :)

The best thing is to get your friend to add a ChangeListener capability to his class - write an addChangeListener(ChangeListener cl) method that stores the ChangeListener, then whenever he updates the data he calls the ChangeListener's stateChanged method. In yhour code you implement the stateChanged method, and call his addChangeListener(this). Now whenever the data changes your stateChanged method will be called. It's exactly the same pattern that Swing uses throughout.

Could you give me a concrete example?
I have read this http://docs.oracle.com/javase/tutorial/uiswing/events/changelistener.html but I still don't understand

All he needs to implement is something like this:

import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;

...

private ChangeListener listener = null;

public void addChangeListener(ChangeListener listener) {
   this.listener = listener;
}

void notifyChangeListener() {
   // he must call this whenever his data is changed
   if (listener != null) 
      listener.stateChanged(new ChangeEvent(this));
   }
}

Then you can use this just like you use any other Swing listener interfaces such as ActionListener

Edited 4 Years Ago by JamesCherrill

This article has been dead for over six months. Start a new discussion instead.