简体   繁体   中英

Trying to use a thread with JProgressBar

So I'm trying to learn how to use threads so I decided to make a program that adds one then waits for 1/2 a sec. while the thread (that I think I made correctly) refreshes the value of the progress bar. So I'm not sure if I've made the program wrong or if it's getting stuck somewhere. So I put a println in the Thread and this is what I get:

thred
0
1
2
3
4
5
6
7
8
9
10
11 (ect...)

Here is my frame code:

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.border.EmptyBorder;

public class frame extends JFrame implements ActionListener{

    private static final long serialVersionUID = 1L;
    private JPanel contentPane;

    public static void main(String[] args) {
        frame f = new frame();
        f.setVisible(true);
        f.setSize(450,120);
    }

    /**
     * Create the frame.
     */

    public JProgressBar bar;

    public frame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 449, 120);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        bar = new JProgressBar();
        bar.setStringPainted(true);
        bar.setBounds(6, 50, 438, 32);
        contentPane.add(bar);

        JLabel lblNewLabel = new JLabel(
                "Percent of for loop completion");
        lblNewLabel.setBounds(6, 6, 279, 16);
        contentPane.add(lblNewLabel);

        JButton btnStart = new JButton("START");
        btnStart.setBounds(327, 1, 117, 29);
        btnStart.addActionListener(this);
        contentPane.add(btnStart);
    }

    public int i, progress;
    public void actionPerformed(ActionEvent e) {
        updater u = new updater();

        u.start();
        for( i =0; i < 100; i++){
            progress = i;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            System.out.println(i);
        }

    }

}

And this is what I think is my thread class:

public class updater extends Thread {

    public void run() {
        System.out.println("thred");
        frame f = new frame();

        int p = f.progress;
        while (p != 100) {

            f.bar.setValue(p);
        }
    }
}

You are blocking Event Dispatching Thread. This is responsible for, amongst other things, processing paint updates. While you block the thread, there is no way the updates can occur, meaning it looks like you program has come to a stand still...

public void actionPerformed(ActionEvent e) {
    updater u = new updater();
    u.start();
    // Now blocking, no more repaints or event notifications until you finish...
    for( i =0; i < 100; i++){
        progress = i;
        try {
            Thread.sleep(500);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println(i);
    }

}

The other problem you have is the fact that Swing (for the most part) is not thread-safe. That is, it is expected that all updates and interactions with the UI will occur only from within the context of the EDT.

While there are a number of ways to get around it, the simplest would be to use a SwingWorker , which is designed to allow you to execute code in a background thread and re-sync updates back to the UI safely.

Take a look at...

For some examples.

You may also want to take a look at Concurrency in Swing for more details

UI programming with threads is tricky, and you can end up with serious problems if multiple threads try to modify UI elements simultaneously. In Swing applications, all updates to the UI should take place on the Swing/AWT event thread. The usual way of doing this is to use EventQueue#invokeLater to schedule a Runnable to execute on the thread; in this case, you'd wrap f.bar.setValue(p); in a Runnable and pass that to invokeLater . Here's a useful tutorial on the basics of the event thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM