1

I have 3 "JProgressBars" in a Java GUI application, which I need to keep updating the values at constant time intervals.

This is my application and highlighted are the progress meters which I want to read the values into.

enter image description here to read the values for each progress meter I have 3 methods in my object (here a robot class) example:

robot.readBattery();
robot.readSonic();
robot.readLight();

All methods will return a value between 0 and 100.

I have seen for a single progress bar this can be done using a swingworker. so does that mean I need 3 swing worker classes in my program to serve all three progress bars?

even if I did that how does the property change listener distinguish among progress bars?

I'll be thankful if somebody could guide me through this.

I have a connect method in robot which returns true if the program is connected to the robot.

ie: boolean connected = robot.connect();

so inside a swingworker the code should be something like ,

while (true) {
    if (connected){
    setProgress(robot.readBattery());
    }

    sleep(1000);
}

I may be wrong. please guide me.

SSCCE as requested:

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;

public class Tester extends JFrame implements PropertyChangeListener,
        ActionListener {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private JProgressBar batteryMeter, lightMeter, sonicMeter;

    private Robot robot = new Robot();
    private BatteryTask bt;

    private JButton start = new JButton("Start");

    public Tester() {

        JPanel statusPanel = new JPanel();
        statusPanel.setLayout(new GridBagLayout());

        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(2, 4, 2, 4);
        c.fill = GridBagConstraints.HORIZONTAL;

        c.gridx = 0;
        c.gridy = 0;
        statusPanel.add(new JLabel("Battery Level:"), c);

        batteryMeter = new JProgressBar(0, 100);
        batteryMeter.setStringPainted(false);
        batteryMeter.setPreferredSize(new Dimension(215, 15));
        batteryMeter.setValue(0);
        c.gridx = 1;
        c.gridy = 0;
        statusPanel.add(batteryMeter, c);

        c.gridx = 0;
        c.gridy = 1;
        statusPanel.add(new JLabel("Light Sensor:"), c);

        lightMeter = new JProgressBar(0, 100);
        lightMeter.setStringPainted(false);
        lightMeter.setPreferredSize(new Dimension(215, 15));
        lightMeter.setValue(0);
        c.gridx = 1;
        c.gridy = 1;
        statusPanel.add(lightMeter, c);
        c.gridx = 0;
        c.gridy = 2;
        statusPanel.add(new JLabel("Ultrasonic Sensor:"), c);

        sonicMeter = new JProgressBar(0, 100);
        sonicMeter.setStringPainted(false);
        sonicMeter.setPreferredSize(new Dimension(215, 15));
        sonicMeter.setValue(0);
        c.gridx = 1;
        c.gridy = 2;
        statusPanel.add(sonicMeter, c);
        c.gridx = 0;
        c.gridy = 3;

            start.addActionListener(this);
        statusPanel.add(start, c);
        this.getContentPane().add(statusPanel);

        this.setSize(500, 300);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setVisible(true);

    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Tester();
            }
        });

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub

        if (e.getSource() == start) {

            bt = new BatteryTask();
            bt.addPropertyChangeListener(this);
            bt.execute();
        }

    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        // TODO Auto-generated method stub
        if ("progress" == evt.getPropertyName()) {
            int progress = (Integer) evt.getNewValue();
            batteryMeter.setValue(progress);
        }

    }

    class BatteryTask extends SwingWorker<Void, Void> {
        /*
         * Main task. Executed in background thread.
         */
        @Override
        public Void doInBackground() {

            // Initialize progress property.
            setProgress(0);
            while (true) {
                // Sleep for up to one second.
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ignore) {
                }
                // Make random progress.

                setProgress(robot.readBattery());
            }
        }

    }

}

class Robot {

    private Random r = new Random();

    int readBattery() {

        int i = r.nextInt(100 - 1) + 1;
        System.out.println(i);
        return i;
    }

    int readSonic() {

        return r.nextInt(100 - 1) + 1;
    }

    int readLight() {

        return r.nextInt(100 - 1) + 1;
    }
}
Sanjan
  • 81
  • 9
  • `may be wrong. please guide me.` ---> no problem, for better helpo sooner post an [SSCCE](http://sscce.org/), short, runnable, compilable, just about `JFrame` contains only one `JProgressBar` with value invoked from `SwingWorker` – mKorbel Sep 23 '13 at 12:11
  • ok let me get back to you with that :) – Sanjan Sep 23 '13 at 12:15
  • @mKorbel Added SSCCE as requested. Thanks for your answer I will take a look at it. – Sanjan Sep 23 '13 at 12:49
  • you never set any value to any of JProgressBars, your SwingWorkers instance isn't touched from any part of code posted here, what do you really want to do, [please see and to test my guide to MVC](http://stackoverflow.com/questions/8169964/is-mvc-in-swing-thread-safe), maybe @HFOE will comment or answering your question too – mKorbel Sep 23 '13 at 12:54
  • @mKorbel I do set the value for batteryMeter progress bar in propertyChange method. – Sanjan Sep 23 '13 at 12:56
  • PropertyChangeListener required notifier, what, where, how a where will be fire notifiers an event(s), again my question what do you (really) want to do, top avoiding any guessing, before any furter discusion to see and try code linked in my last comment – mKorbel Sep 23 '13 at 12:58

3 Answers3

3

I have seen for a single progress bar this can be done using a swingworker. so does that mean I need 3 swing worker classes in my program to serve all three progress bars?

  • not neccessary, its about code design

even if I did that how does the property change listener distinguish among progress bars?

  • no idea without posting your SSCCE

  • Thread.sleep(int) isn't about good practicies in Java, but inside doInBackground() haven't any negatice whatever, only freeze loop for sleep period


  • four different methods for How to move with progress

enter image description here .

enter image description here

import java.awt.*;
import java.awt.event.ActionEvent;
import java.beans.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import javax.swing.table.*;

public class TableIcon extends JFrame implements Runnable {

    private static final long serialVersionUID = 1L;
    private JTable table;
    private JLabel myLabel = new JLabel("waiting");
    private JLabel lastRunLabel = new JLabel("waiting");
    private int pHeight = 40;
    private boolean runProcess = true;
    private int count = 0;
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    private ScheduledExecutorService scheduler;
    private AccurateScheduledRunnable periodic;
    private ScheduledFuture<?> periodicMonitor;
    private Executor executor = Executors.newCachedThreadPool();
    private Date dateLast;
    private Date dateNext;
    private Date dateRun;
    private int taskPeriod = 1;
    private int dayCount = 0;
    private int hourCount = 0;
    private int minuteCount = 0;
    private int secondCount = 0;
    private Timer timerRun;
    private int delay = 3000;
    private boolean bolo = false;

    public TableIcon() {
        ImageIcon errorIcon = (ImageIcon) UIManager.getIcon("OptionPane.errorIcon");
        ImageIcon infoIcon = (ImageIcon) UIManager.getIcon("OptionPane.informationIcon");
        ImageIcon warnIcon = (ImageIcon) UIManager.getIcon("OptionPane.warningIcon");
        String[] columnNames = {"Picture", "Description"};
        Object[][] data = {{errorIcon, "About"}, {infoIcon, "Add"}, {warnIcon, "Copy"},};
        DefaultTableModel model = new DefaultTableModel(data, columnNames) {

            private static final long serialVersionUID = 1L;

            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }
        };
        table = new JTable(model);
        table.setRowHeight(pHeight);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane, BorderLayout.CENTER);
        lastRunLabel.setPreferredSize(new Dimension(200, pHeight));
        lastRunLabel.setHorizontalAlignment(SwingConstants.CENTER);
        add(lastRunLabel, BorderLayout.NORTH);
        myLabel.setPreferredSize(new Dimension(200, pHeight));
        myLabel.setHorizontalAlignment(SwingConstants.CENTER);
        add(myLabel, BorderLayout.SOUTH);
        scheduler = Executors.newSingleThreadScheduledExecutor();
        periodic = new AccurateScheduledRunnable() {

            private final int ALLOWED_TARDINESS = 200;
            private int countRun = 0;
            private int countCalled = 0;

            @Override
            public void run() {
                countCalled++;
                if (this.getExecutionTime() < ALLOWED_TARDINESS) {
                    countRun++;
                    executor.execute(new TableIcon.MyTask("GetCurrTime")); // non on EDT
                }
            }
        };
        periodicMonitor = scheduler.scheduleAtFixedRate(periodic, 0, taskPeriod, TimeUnit.MINUTES);
        periodic.setThreadMonitor(periodicMonitor);
        new Thread(this).start();
        prepareStartShedule();
    }

    private void prepareStartShedule() {
        timerRun = new javax.swing.Timer(delay, startCycle());
        timerRun.setRepeats(true);
        timerRun.start();
    }

    private Action startCycle() {
        return new AbstractAction("Start Shedule") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                executor.execute(new TableIcon.MyTask("StartShedule")); // non on EDT
            }
        };
    }

    private void changeTableValues() {
        Runnable doRun = new Runnable() {

            @Override
            public void run() {
                if (bolo) {
                    bolo = false;
                    table.getModel().setValueAt("*/*/*/**/*/*/*", 0, 1);
                    table.getModel().setValueAt(" k k k k k k k k", 1, 1);
                    table.getModel().setValueAt("@#@#@#@", 2, 1);
                } else {
                    bolo = true;
                    table.getModel().setValueAt("Green Peper", 0, 1);
                    table.getModel().setValueAt("Yellow Apple", 1, 1);
                    table.getModel().setValueAt("Orange Bus", 2, 1);
                }
            }
        };
        SwingUtilities.invokeLater(doRun);
    }

    private void distAppInfo() {
        Runnable doRun = new Runnable() {

            @Override
            public void run() {
                dateNext = new java.util.Date();
                dateLast = new java.util.Date();
                long tme = dateNext.getTime();
                tme += (taskPeriod * 60) * 1000;
                dateNext.setTime(tme);
                lastRunLabel.setText("Last : " + sdf.format(dateLast) + " / Next : " + sdf.format(dateNext));
            }
        };
        SwingUtilities.invokeLater(doRun);
    }

    private void changeLabelColor() {
        Runnable doRun = new Runnable() {

            @Override
            public void run() {
                Color clr = lastRunLabel.getForeground();
                if (clr == Color.red) {
                    lastRunLabel.setForeground(Color.blue);
                } else {
                    lastRunLabel.setForeground(Color.red);
                }
            }
        };
        SwingUtilities.invokeLater(doRun);
    }

    @Override
    public void run() {
        while (runProcess) {
            try {
                Thread.sleep(5000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            executor.execute(new TableIcon.MyTask("ChangeIconLabel")); // non on EDT
        }
    }

    private void setIconLabel() {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                String text = "";
                dateRun = new java.util.Date();
                long tme = dateRun.getTime();
                long she = periodicMonitor.getDelay(TimeUnit.SECONDS);
                dayCount = (int) (she / (24 * 60 * 60));
                hourCount = (int) (she / (60 * 60));
                minuteCount = (int) (she / (60));
                secondCount = (int) she;
                int hourss = hourCount;
                int minutess = minuteCount;
                if (dayCount > 0) {
                    hourCount -= (dayCount * 24);
                    minuteCount -= ((dayCount * 24 * 60) + (hourCount * 60));
                    secondCount -= (minutess * 60);
                    //System.out.println(" Days : " + dayCount + "  ,Hours : " + hourCount + "  , Minutes : " + minuteCount + "  , Seconds : " + secondCount);
                    text = ("  " + dayCount + " Days  " + hourCount + " h : " + minuteCount + " m : " + secondCount + " s");
                } else if (hourCount > 0) {
                    minuteCount -= ((hourss * 60));
                    secondCount -= (minutess * 60);
                    //System.out.println(" Hours : " + hourCount + "  , Minutes : " + minuteCount + "  , Seconds : " + secondCount);
                    text = ("  " + hourCount + " h : " + minuteCount + " m : " + secondCount + " s");
                } else if (minuteCount > 0) {
                    secondCount -= (minutess * 60);
                    //System.out.println(" Minutes : " + minuteCount + "  , Seconds : " + secondCount);
                    text = ("  " + minuteCount + " m : " + secondCount + " s");
                } else {
                    //System.out.println(" Seconds : " + secondCount);
                    text = ("  " + secondCount + " s");
                }
                tme += she * 1000;
                ImageIcon myIcon = (ImageIcon) table.getModel().getValueAt(count, 0);
                String lbl = "Row at :  " + count + "  Remains : " + text;
                myLabel.setIcon(myIcon);
                myLabel.setText(lbl);
                count++;
                if (count > 2) {
                    count = 0;
                }
            }
        });
    }

    public static void main(String[] args) {
        TableIcon frame = new TableIcon();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setLocation(150, 150);
        frame.pack();
        frame.setVisible(true);
    }

    private class MyTask extends SwingWorker<Void, Integer> {

        private String str;
        private String namePr;

        MyTask(String str) {
            this.str = str;
            addPropertyChangeListener(new SwingWorkerCompletionWaiter(str, namePr));
        }

        @Override
        protected Void doInBackground() throws Exception {
            if (str.equals("GetCurrTime")) {
                distAppInfo();
            } else if (str.equals("ChangeIconLabel")) {
                setIconLabel();
            } else if (str.equals("StartShedule")) {
                changeTableValues();
            }
            return null;
        }

        @Override
        protected void process(List<Integer> progress) {
            //System.out.println(str + " " + progress.get(progress.size() - 1));
        }

        @Override
        protected void done() {
            if (str.equals("GetCurrTime")) {
                changeLabelColor();
            } else if (str.equals("ChangeIconLabel")) {
                //setIconLabel();
            } else if (str.equals("StartShedule")) {
                //changeTableValues();
            }
        }
    }

    private class SwingWorkerCompletionWaiter implements PropertyChangeListener {

        private String str;
        private String namePr;

        SwingWorkerCompletionWaiter(String str, String namePr) {
            this.str = str;
            this.namePr = namePr;
        }

        SwingWorkerCompletionWaiter(String namePr) {
            this.namePr = namePr;
        }

        @Override
        public void propertyChange(PropertyChangeEvent event) {
            if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) {
                System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) {
                System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) {
                System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else {
                System.out.println("SomeThing Wrong happends with Thread Status with Name :" + str);
            }
        }
    }
}

abstract class AccurateScheduledRunnable implements Runnable {

    private ScheduledFuture<?> thisThreadsMonitor;

    public void setThreadMonitor(ScheduledFuture<?> monitor) {
        this.thisThreadsMonitor = monitor;
    }

    protected long getExecutionTime() {
        long delay = -1 * thisThreadsMonitor.getDelay(TimeUnit.MILLISECONDS);
        return delay;
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
3

The PropertyChangeEvent named "progress" communicates only a single value, and the worker's progress as a whole is irrelevant. Instead, let a single RobotTask background thread publish() a StatusRecord holding the three new values. The worker's process() method, which executes on the event dispatch thread, can update the three progress bars as new records arrive. There are related examples here and here.

class RobotTask extends SwingWorker<StatusRecord, StatusRecord> {…}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
0

Based on answer from @trashgod, I modified my code. which is working as expected.

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;

public class Tester extends JFrame implements ActionListener {

    private static final long serialVersionUID = 1L;

    private JProgressBar batteryMeter, lightMeter, sonicMeter;

    private Robot robot = new Robot();
    private ReadSensorTask readSensor;

    private JButton start = new JButton("Start");

    public static void main(String[] args) {

        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Tester();
            }
        });

    }

    public Tester() {

        JPanel statusPanel = new JPanel();
        statusPanel.setLayout(new GridBagLayout());

        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(2, 4, 2, 4);
        c.fill = GridBagConstraints.HORIZONTAL;

        c.gridx = 0;
        c.gridy = 0;
        statusPanel.add(new JLabel("Battery Level:"), c);

        batteryMeter = new JProgressBar(0, 100);
        batteryMeter.setStringPainted(false);
        batteryMeter.setPreferredSize(new Dimension(215, 15));
        batteryMeter.setValue(0);
        c.gridx = 1;
        c.gridy = 0;
        statusPanel.add(batteryMeter, c);

        c.gridx = 0;
        c.gridy = 1;
        statusPanel.add(new JLabel("Light Sensor:"), c);

        lightMeter = new JProgressBar(0, 100);
        lightMeter.setStringPainted(false);
        lightMeter.setPreferredSize(new Dimension(215, 15));
        lightMeter.setValue(0);
        c.gridx = 1;
        c.gridy = 1;
        statusPanel.add(lightMeter, c);
        c.gridx = 0;
        c.gridy = 2;
        statusPanel.add(new JLabel("Ultrasonic Sensor:"), c);

        sonicMeter = new JProgressBar(0, 100);
        sonicMeter.setStringPainted(false);
        sonicMeter.setPreferredSize(new Dimension(215, 15));
        sonicMeter.setValue(0);
        c.gridx = 1;
        c.gridy = 2;
        statusPanel.add(sonicMeter, c);
        c.gridx = 0;
        c.gridy = 3;

        start.addActionListener(this);
        statusPanel.add(start, c);
        this.getContentPane().add(statusPanel);

        this.setSize(500, 300);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setVisible(true);

    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getSource() == start) {

            readSensor = new ReadSensorTask();
            readSensor.execute();
        }

    }

    private class RobotValues {
        private int sonic, light, battery;

        RobotValues(int b, int l, int s) {

            this.light = l;
            this.battery = b;
            this.sonic = s;

        }

    }

    class ReadSensorTask extends SwingWorker<Void, RobotValues> {
        /*
         * Main task. Executed in background thread.
         */
        @Override
        public Void doInBackground() {

            while (true) {

                publish(new RobotValues(robot.readBattery(), robot.readLight(),
                        robot.readSonic()));
                // Sleep for up to one second.
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ignore) {
                }

            }
        }

        @Override
        protected void process(List<RobotValues> rbv) {

            RobotValues rb = rbv.get(rbv.size() - 1);
            batteryMeter.setValue(rb.battery);
            sonicMeter.setValue(rb.sonic);
            lightMeter.setValue(rb.light);

        }

    }

}

class Robot {

    private Random r = new Random();

    int readBattery() {

        int i = r.nextInt(100 - 1) + 1;
        return i;
    }

    int readSonic() {

        return r.nextInt(100 - 1) + 1;
    }

    int readLight() {

        return r.nextInt(100 - 1) + 1;
    }
}
Sanjan
  • 81
  • 9