dev-cyprium
dev-cyprium

Reputation: 768

Button ActionListener

Ok, so I made a simple program that adds the value to counter each time a button is clicked. Now, I would like to add "Auto" button feature to increase the value of the counter when the "Auto" button is clicked. I'm having problems with it because it won't render each counter value on the screen, instead the value updates when the loop is done.. Here is my code:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JFrame;


public class Gui extends JFrame{

    private static final long serialVersionUID = 1L;

    private JButton uselesButton;

    private JButton autoButton;

    private FlowLayout layout;
    private long counter = 0;

    public Gui() {
        super("Button");
        layout = new FlowLayout(FlowLayout.CENTER);
        this.setLayout(layout);

        uselesButton = new JButton(String.format("Pressed %d times", counter));
        add(uselesButton);
        uselesButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                counter++;
                uselesButton.setText(String.format("Pressed %d times", counter));
            }

        });

        autoButton = new JButton("Auto");
        add(autoButton);
        autoButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                        for(long i =0; i < 99999999;i++) {
                        try {
                            TimeUnit.MILLISECONDS.sleep(10);
                        } catch (InterruptedException e1) {
                            System.out.println("ERROR");
                        }
                        counter = i;
                        uselesButton.setText(String.format("Pressed %d times", counter));
                    }
                    }
        });
    }
}

Keep in mind that I'm a beginner... All help appreciated :)

Upvotes: 8

Views: 101482

Answers (3)

Azad
Azad

Reputation: 5055

Take a look at the tutorial about How to Use Swing Timer and then look at my solution:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;

public class Gui extends JFrame {

    private static final long serialVersionUID = 1L;
    private JButton uselesButton;
    private JButton autoButton;
    private FlowLayout layout;
    private long counter = 0;
    private javax.swing.Timer timer;

    public Gui() {
        super("Button");
        layout = new FlowLayout(FlowLayout.CENTER);
        setLayout(layout);
        setDefaultCloseOperation(3);
        setSize(300, 300);
        setLocationRelativeTo(null);

        //initialing swing timer
        timer = new javax.swing.Timer(100, getButtonAction());

        autoButton = new JButton("Auto");
        add(autoButton);
        autoButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (!timer.isRunning()) {
                    timer.start();
                } else {
                    timer.stop();
                }
            }
        });
    }

    private ActionListener getButtonAction() {
        ActionListener action = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                autoButton.setText(String.format("Pressed %d times", ++counter));
                if (counter > 1000) {
                    timer.stop();
                }
            }
        };
        return action;
    }

    public static void main(String... args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Gui().setVisible(true);
            }
        });
    }
}

Upvotes: 6

Wajdy Essam
Wajdy Essam

Reputation: 4340

your code block the GUI thread (EDT) when enter inside this loop (GUI will hang, the button will not update until you finish), so you should add your code inside another worker thread:

autoButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for(long i =0; i < 99999999;i++) {
                                try {
                                    TimeUnit.MILLISECONDS.sleep(10);
                                } catch (InterruptedException e1) {
                                    System.out.println("ERROR");
                                }
                                counter = i;

                                java.awt.EventQueue.invokeLater(new Runnable() {
                                      public void run() {
                                         uselesButton.setText(String.format("Pressed %d times", counter));
                                      }
                                });
                            }
                        }
                    }).start();
            }
        });

Upvotes: 1

No Idea For Name
No Idea For Name

Reputation: 11597

the problem here is that the system is in the loop, so it can't paint the changes. in order to do that you need to open a new thread. the new thread will do the loop, and the main thread will repaint the form.

one more thing, you shouldn't do sleep on the main thread. you can use a timer that will tick every 10 millisecond instead of sleep(10) here is an example

Upvotes: 0

Related Questions