BSeitkazin
BSeitkazin

Reputation: 3059

Update JTable in SwingWorker

I have a JTable which populates data from DB. I want to refresh data in JTable every 10 minutes (for testing 10 sec is enough). I tried do it with a Thread, but I found that it is not good idea, and I need to use SwingWorker

public class Monitor extends JFrame{

    JTable jtable = null;
    JTabbedPane jtp = null;
    JPanel jp1 = null;
    JPanel jp2 = null;
    JLabel label1 = null;
    JLabel label2 = null;

    public void setJTable(Vector data, Vector columnNames) {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jtable = new JTable(data, columnNames);
        JScrollPane scrollPane = new JScrollPane(jtable);
        jp1.add(scrollPane);
    }

    public void updateJTable(Vector data, Vector columnNames) {
        jtable = new JTable(data, columnNames);
    }

    public Monitor() {

        setTitle("Monitor System");

        //Panel with tabs for navigation
        jtp = new JTabbedPane();
        getContentPane().add(jtp);

        //tab1, info from dba_jobs
        jp1 = new JPanel();

        //tab2 info from QueueInfo
        jp2 = new JPanel();
        label1 = new JLabel();
        label1.setText("tab1");

        label2 = new JLabel();
        label2.setText("tab2");

        jp1.add(label1);
        jp2.add(label2);

        jtp.add("Tab1", jp1);
        jtp.add("Tab2", jp2);
    }

}

And my Demo class:

public class Demo {

    public static void main(String[] args) throws ClassNotFoundException, SQLException  {

        Statement stmt = null;
        Connection conn = null;
        ResultSet rs = null;
        Vector<String> columnNames = new Vector<String>();
        Vector<Vector> rowData = new Vector<Vector>();
        DBMonitor dbmonitor = new DBMonitor();
        Monitor monitor = new Monitor();

        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

        rowData = dbmonitor.getJobsData();
        columnNames = dbmonitor.getColumnNames();
        monitor.setJTable(rowData, columnNames);
        monitor.setSize((int) dim.getWidth(), (int) dim.getHeight());
        monitor.setVisible(true);

        boolean interrupt = true;

        while (interrupt) {
            try {

                rowData = dbmonitor.getJobsData();
                columnNames = dbmonitor.getColumnNames();
                monitor.updateJTable(rowData, columnNames);
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException ie) {
                    return;
                } 
                JOptionPane.showMessageDialog(null, "SLEEP!");

            } catch (Exception e) {
                JOptionPane.showMessageDialog(null, e.getMessage());
                System.err.println(e.getMessage());
            }
        }

    }
}

How I can do it with SwingWorker? I don't get a concept of that way.

Upvotes: 0

Views: 2297

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

First, I would start with a Timer of some sort, I'm going to use a Swing Timer as it easy, but you could use a java.util.Timer instead...

private Timer updateTimer;

//...

updateTimer = new Time(10000, new ActionListener() {
    public void actionListener(ActionEvent e) {
    }
});
updateTimer.setRepeats(false);
updateTimer.start();

This allows you to be notified in about 10 seconds time...

Then you need a SwingWorker that can do the actual work...

public class UpdateWorker extends SwingWorker<TableModel, Void> {

    private Monitor monitor;
    private Timer updateTimer;

    public UpdateWorker(Monitor monitor, Timer updateTimer) {
        this.monitor = monitor;
        this.updateTimer = updateTimer;
    }

    @Override
    protected TableModel doInBackground() throws Exception {
        Vector<Vector> rowData = dbmonitor.getJobsData();
        Vector columnNames = dbmonitor.getColumnNames();

        DefaultTableModel model = new DefaultTableModel(rowData, columnNames);
        return model;
    }

    @Override
    protected void done() {
        try {
            TableModel model = get();
            monitor.updateTable(model);
        } catch (InterruptedException | ExecutionException ex) {
            ex.printStackTrace();
        }
        updateTimer.restart();
    }
}

Now in the actionPerformed method of the ActionListener assigned to the timer, you would do something like..

public void actionListener(ActionEvent e) {
    UpdateWorker worker = new UpdateWorker(monitor, this);
    worker.execute();
}

To execute the worker. The reason for having a non-repeating timer is to ensure that the next update is set for n seconds from when the update completes, so you don't get overlapping updates

Oh, and this will require to update your Monitor to accept a TableModel rather then the Vectors you are using to create one, it's just simpler that way...

Upvotes: 1

camickr
camickr

Reputation: 324108

In the doInBackground() method of the SwingWorker you have you while loop that:

  1. retrieves the data from the database
  2. creates your TableModel
  3. use the publish() method of the SwingWorker to pass the TableModel to the 'process()` method of your SwingWorker
  4. sleeps for 10 seconds

Then in the process() method of the SwingWorker you:

  1. use the TableModel that was passed to the process() method to update your JTable.

Read the section from the Swing tutorial on Concurrency for more information and a working example or search the forum for more SwingWorker examples.

Upvotes: 2

Related Questions