Search code examples
javamultithreadingjlabelswingworker

How would i make a JLabel text be changed automatically?


well When downloading a jar i want it to print on a jlabel % downloaded so far, but the way i implemented when i start the download it starts off at 0% ofcourse but even after downloading it doesn't show the new percantage.

heres my code :

            while(( length = inputstream.read(buffer)) > -1)
            {
                down += length;
                bufferedoutputstream.write(buffer, 0 , length);
                String text = clientDL.label1.getText();
                int perc = getPerc();
                text = "Currently downloading , " + perc + "% finished...";
            }

and heres my getPerc() method :

    private  int getPerc() {

    return  (down / (sizeOfClient + 1)) * 100;
}

update :

i made it run on a seperate thread, but still the same

                while(( length = inputstream.read(buffer)) > -1)
            {
                down += length;
                bufferedoutputstream.write(buffer, 0 , length);
                thread = new Thread(new Runnable() {
                    public void run() {
                    clientDL.label1.setText("Downloading Client : " + getPerc() + " % Done.");
                    }
                });
            }

Solution

  • Automatically would be nice, but you will have a little work to do in order to have your number increment by itself. As previously stated you have two options:

    • Use a Thread, a class that implements Runnable or
    • Use a SwingWorker that extends SwingWorker, which is also a thread, but comes with full control capabilities built in.

    In case you use a Thread, pass your JLabel to the constructor in order to be able to easily modify it's text as your thread progresses.

    If you choose to use a SwingWorker create an inner class that does the work and implement doInBackground(), process() and done().

    Here are two solutions using sleep(60) instead of a file download as a delay. Substitute this line with a call to a download method.

    A SwingWorker approach:

    public class LabelWorker extends JFrame {
    
        private class Task extends SwingWorker<Void, Integer> {
    
            @Override
            protected Void doInBackground() {
                val = 0;
                setProgress(0);
                while (val < 1000) {
                    try {
                        Thread.sleep(60);
                    } catch (InterruptedException ex) {
                    }
                    publish(val);
                    setProgress((int) (val * 100. / 1000.));
                    val++;
                }
                return null;
            }
    
            @Override
            protected void process(List<Integer> chunks) {
                progressLbl.setText(chunks.get(0).toString());
            }
    
            @Override
            public void done() {
                startBtn.setEnabled(true);
                setCursor(null);
                val = 1000;
            }
            private int val;
    
        }
    
        public LabelWorker() {
            setTitle("Worker");
            setLayout(new FlowLayout());
            startBtn = new JButton("Start");
            startBtn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent evt) {
                    actionStart();
                }
            });
            stopBtn = new JButton("Stop");
            stopBtn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent evt) {
                    actionStop();
                }
            });
            progressLbl = new JLabel("not running...");
            add(startBtn);
            add(stopBtn);
            add(progressLbl);
            pack();
        }
    
        private void actionStart() {
            Task task;
            startBtn.setEnabled(false);
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            task = new Task();
            task.execute();
            t = task;
        }
    
        private void actionStop() {
            startBtn.setEnabled(true);
            setCursor(null);
            t.cancel(true);
        }
    
        public static void main(String[] args) {
            new LabelWorker().setVisible(true);
        }
        private final JButton startBtn;
        private final JButton stopBtn;
        private final JLabel progressLbl;
        private Task t;
    }
    

    A Runnable thread approach:

    public class ProgressingLabels extends JFrame {
    
        private class Loader implements Runnable {
    
            private final JLabel progress;
    
            public Loader(JLabel progress) {
                this.progress = progress;
                progress.setText("0");
            }
    
            @Override
            public void run() {
                int i = 0;
                while (i < 1000) {
                    progress.setText(String.valueOf(++i));
                    try {
                        TimeUnit.MILLISECONDS.sleep(60);
                    } catch (InterruptedException ex) {
                        break;
                    }
                }
            }
        }
    
        public ProgressingLabels() {
            startButton = new JButton("Start");
            stopButton = new JButton("Stop");
            progressLabel = new JLabel("0     ");
    
            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
            setLayout(new FlowLayout());
    
            startButton.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    if ((wt == null) || (!wt.isAlive())) {
                        Loader ld = new Loader(progressLabel);
                        wt = new Thread(ld);
                        wt.start();
                    } else {
                        JOptionPane.showMessageDialog(null, "Thread already running...");
                    }
                }
            });
            add(startButton);
    
            stopButton.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    if ((wt != null) && (wt.isAlive())) {
                        wt.interrupt();
                    }
                    JOptionPane.showMessageDialog(null, "Thread interrupted\n" + (progressLabel.getText()) + " rounds.");
                }
            });
            add(stopButton);
    
            add(progressLabel);
    
            pack();
        }
    
        public static void main(String args[]) {
            java.awt.EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new ProgressingLabels().setVisible(true);
                }
            });
        }
    
        private final JButton startButton;
        private final JButton stopButton;
        private JLabel progressLabel;
        private Thread wt;
    }
    

    The thread classes could also be written in separate files. I put them in inner classes just in order to make this code more compact.

    For file downloads, I think, you should rather use a JProgressBar instead of a JLabel.