Thread sleep in actionPerformed - java

I am trying to make a tiny program that has 3 buttons, all of them of white color. Pressing the first button (that has the text "Go!") will cause the second button to become orange for 3 seconds and then, after that time, it will become white again AND the third button will become permanently green.
However, in my following code, I have a problem achieving this: When hitting the button "Go!", it causes my program to somewhat freeze for 3 seconds and then the third button becomes green. Can you please help me?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Example extends JFrame
{
public Example(String title)
{
super(title);
GridLayout gl = new GridLayout(3,1);
setLayout(gl);
final JButton b1 = new JButton("Go!");
final JButton b2 = new JButton();
final JButton b3 = new JButton();
b1.setBackground(Color.WHITE);
b2.setBackground(Color.WHITE);
b3.setBackground(Color.WHITE);
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b2.setBackground(Color.ORANGE);
try
{
Thread.sleep(3000);
} catch (InterruptedException ie) {}
b2.setBackground(Color.WHITE);
b3.setBackground(Color.GREEN);
}
});
add(b1);
add(b2);
add(b3);
setSize(50,200);
setVisible(true);
}
public static void main(String[] args)
{
Example ex = new Example("My Example");
}
}

Swing is single threaded. Calling Thread.sleep in the EDT prevents UI updates. Use a Swing Timer instead.

You're calling Thread.sleep(3000) on the main thread. Hence why your program freezes for three seconds. As #MarounMaroun suggested, you should use a SwingWorker. Here is the documentation.

Related

Adding a action listener in java for a counter

I am a fairly new user with programming in Java with about a week and a bit experience, as of before I have been using python for about 3 years but thought to give java a try.
I have been trying to develop my skills by creating small projects and applications and am now creating a small GUI counter.
I have achieved creating the GUI with 2 buttons and a label and have tested the maths behind the application but I am struggling to work out how the ActionListener works as it feels a lot different to python when making a button have a action.
This is My Code;
package gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
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.JTextField;
import javax.swing.*;
public class GUI{
//This creates a frame or panel to contain things
public static void main(String[] args) {
//Maths To The Counter
int Counter = 0;
System.out.println(Counter);
Counter =+ 1;
System.out.println(Counter);
//Creating The Frame
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.WHITE);
frame.getContentPane().add(panel);
//Creating The Label
JLabel label3 = new JLabel("Counter: ");
panel.add(label3);
//Button Which should have a funtion to add and display the number
JButton button = new JButton("Click Here.");
panel.add(button);
//Button to reset the counter
JButton buttonReset = new JButton("Reset Counter.");
panel.add(buttonReset);
//Set Size Of Window
frame.setSize(new Dimension(500, 400));
//Set Starting Position to centre
frame.setLocationRelativeTo(null);
//Setting a default close action
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set Title
frame.setTitle("Counter");
//Disable Resize
frame.setResizable(false);
//Setting if its visible
frame.setVisible(true);
//Fits frame to fit everything
frame.pack();
}
}
enter code here
I know that in python a action is in a function so that has been my logic to this problem however I have seen that I need to use the actionlistener instead and I am struggling to get my head around it.
If Someone could show me how this type of action should be implemented it would be great help, I have watch some youtube videos and done a bit of research but im still struggling to understand in my situation how to do it.
For any confussion im sorry, overall my question is how do I add a action to a button in my program that can implement my maths at the start.
As well any feedback on the structure of my code would be welcomed as I am just starting in java and I do know poor structure can lead to mistakes.
This code should work:
Basically, in the main method I am creating an instance of the class and calling a method to create the gui.
I also created an instance variable as the counter, otherwise you won't be able to update the variable in your action listener.
public class Gui {
private int counter;
// This creates a frame or panel to contain things
public static void main(String[] args) {
Gui gui = new Gui();
gui.create();
}
private void create() {
// Creating The Frame
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.WHITE);
frame.getContentPane().add(panel);
// Creating The Label
JLabel label3 = new JLabel("Counter: ");
panel.add(label3);
// Button Which should have a funtion to add and display the number
JButton button = new JButton("Click Here.");
panel.add(button);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(counter++);
}
});
// Button to reset the counter
JButton buttonReset = new JButton("Reset Counter.");
panel.add(buttonReset);
buttonReset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter = 0;
}
});
// Set Size Of Window
frame.setSize(new Dimension(500, 400));
// Set Starting Position to centre
frame.setLocationRelativeTo(null);
// Setting a default close action
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set Title
frame.setTitle("Counter");
// Disable Resize
frame.setResizable(false);
// Setting if its visible
frame.setVisible(true);
// Fits frame to fit everything
}
}
With Lambda expressions, you can simplify your action listeners as follows:
button.addActionListener(a -> System.out.println(counter++));
buttonReset.addActionListener(a -> counter = 0);
If you want to write more than 1 statement, then you can just put your code in curly brackets:
button.addActionListener(a -> {
System.out.println(counter++);
System.out.println("doing more stuff...");
});
JButton has a function called addActionListener. You can pass on an action listener by doing this:
button.addActionListener(() -> {
// Do some logic here
});
Here, I use a lambda expression as an action listener. Within the lambda expression you can place whatever logic you want to have.
Also note that you can add multiple different action listeners to the same button. In a nutshell, the way the JButton interacts with the ActionListeners is based on the observer-pattern.
Imagine this: When the JButton is pressed, it will notify all of it's observers saying "Hey, I have been pressed". Each observer can then independently decide what to do. In case of the JButton, all observers are ActionListeners. If you add multiple ActionListeners then the JButton will notify all of them, and as a result all of their actionPerformed(ActionEvent e) functions are executed. In the example above, I used a lambda expression which then by java is interpreted as an ActionListener.
Other ways to achieve the exact same functionality are:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Do some logic here
}
});
In the example above, you use an anonymous class as an actionlistener.
public class MyClass {
public MyClass() {
JButton button = new JButton("press me");
button.addActionListener(new MyActionListener());
}
private class MyActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// Do some logic here
}
}
}
In the example above, an inner class is used.
In a nutshell, there is a ton of ways you can make your button have functionality. Above are just a few examples of how to do so.
Does this clarify it a bit more, or do you have some remaining questions?

Thread.sleep() crashes my GUI

My Thread.sleep(rand.nextInt(delay)) command in my ButtonListener class crashes my GUI. Any ideas? The program is supposed to add people to an ArrayList, then randomly select them and display them at a random time between 0 and the timeText JTextField, and it works until I add the sleep command. Any help would be appreciated thanks!
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
import javax.swing.Timer;
public class MyProgram extends AppClass{
protected int x,y,width,height;
protected Color color;
private ArrayList<String> people = new ArrayList<String>();
private static JLabel person;
private Timer timer;
private ButtonListener listener;
private Random rand = new Random();
private JLabel addPeople;
private JTextField newPerson;
private JTextField timeText;
private Font font1 = new Font("Arial",1,17);
private Font font2 = new Font("Arial",1,65);
public MyProgram(){
setPreferredSize(new Dimension(1000,800));
people.add("me");
people.add("john");
people.add("greg");
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(600,400));
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
newPerson = new JTextField(2);
newPerson.setFont(font1);
addPeople = new JLabel("Add people:");
addPeople.setFont(font1);
person = new JLabel();
person.setFont(font2);
JButton addButton = new JButton("Add");
addButton.setFont(font1);
JButton startButton = new JButton("Start");
startButton.setFont(font1);
timeText = new JTextField(2);
timeText.setFont(font1);
JLabel time = new JLabel("Maximum time between draws:");
time.setFont(font1);
listener = new ButtonListener();
addButton.addActionListener(listener);
startButton.addActionListener(listener);
panel.add(addPeople);
panel.add(newPerson);
panel.add(addButton);
panel.add(time);
panel.add(timeText);
panel.add(startButton);
panel.add(person);
add(panel);
}
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent ae){
JButton button = (JButton) ae.getSource();
if(button.getText().equals("Add")){
people.add(newPerson.getText());
System.out.println(newPerson.getText());
System.out.println("also worked");
}else if(button.getText().equals("Start")){
int delay = Integer.parseInt(timeText.getText());
for(;;){
person.setText(people.get(rand.nextInt(people.size())));
try{
Thread.sleep(rand.nextInt(delay)); // the problem
}catch(Exception error){
System.out.println("Error");
}
}
}
}
}
}
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
import javax.swing.Timer;
public class AppClass extends JPanel{
public static void main(String [] args){
JFrame frame = new JFrame();
frame.getContentPane().add(new Get());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setTitle("My Program");
}
}
There is only one thread that modifies the UI. This is by design, because it means that, even with the many sources of events that a UI could receive, it is impossible for concurrency bugs to corrupt the UI state.
There is only one thread that modifies the UI. That includes:
Receiving mouse events.
Receiving keyboard events.
Processing requests to repaint.
Processing UI timers.
Among many others.
If you're in code that modifies the UI, then you must be on the UI thread (else, you have a bug). If you're on the UI thread and you call Sleep(), then the UI thread stops doing things.
It'll stop responding to requests to repaint. It'll stop responding to keyboard events, mouse events, etc.
Instead, you have to use a forms timer to perform an animation. When someone clicks your "Start" button, you would set the first value, save off the rest of the values, and then start your timer, and then let the UI thread keep processing.
Each time the timer fires, you advance the state - you update the UI with the next value you want to show. You continue this until you've shown all values, and then stop the timer and release your state that told you where you were in the animation.
Yeah, you're just setting the text on some component, but this still falls under the animation pattern.
Be careful though - if your UI is closed while the animation timer is still running, you'll try to modify a UI that is gone. So now your UI code has to be careful to stop the animation timer if it's still running when the UI is closed.
actually, you are execute your gui into same thread and when you are use Thread.sleep(delay) you are also sleep you gui. so you have to use new thread for other processing.
Thread t = new Thread(new Runnable(){
#Override
public void run() {
}
});

How to enable buttons at start of gui in Netbeans

This is not a duplicate as I already know the code .setEnabled(false);. My problem is that I am making a gui in netbeans and I cannot figure out how to disable/enable buttons. Obviously I am new to JAVA and Netbeans This is what I have to do:
Start the program with all buttons disabled except the Initialize
button.
When Initialize is pressed the ArrayList will be filled with 5 CD
titles. The Initialize button then becomes disabled and the other
buttons become enabled.
The only code I know for buttons is .setEnabled(false); but it only disables button after I click it and what i need is to make one enabled and rest disabled. After I click it, it should be disabled and rest should be enabled.
The current code is not relevant but if you need it I will edit this post! Any help is greatly appreciated and thank you in advance!
You need to use interface ActionListener and add ActionListener after clicking
of button. Implement default method ActionPerformed. Use this code as example.
import java.awt.*;
import java.awt.event.*;
class calc extends Frame implements ActionListener
{
TextField t1 =new TextField(20);
TextField t2 =new TextField(29);
TextField t3 =new TextField(29);
Label l1=new Label("first");
Label l2=new Label("second");
Label l3=new Label("sum");
Button b1=new Button("Add");
Button b2=new Button("close");
calc() //CONSTRUCTOR
{
add(l1);add(t1);
add(t2);add(l2);
add(t3);add(l3);
add(b1);
add(b2);
setSize(444,555);
setVisible(true);
setLayout(new FlowLayout());
b1.addActionListener(this);
b2.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
Object o=e.getSource();
if(o==b2)
{
System.exit(1);
}
String n1=t1.getText();
String n2=t2.getText();
int a=Integer.parseInt(n1);
int b=Integer.parseInt(n2);
t3.setText(""+(a+b));
}
}
class Gi
{
public static void main(String[] args)
{
new calc();
}
}

How can I keep executing work while a button is pressed?

I want to keep executing work while a button is pressed, using Java. When the button is released, the work should stop. Something like this:
Button_is_pressed()
{
for(int i=0;i<100;i++)
{
count=i;
print "count"
}
}
How might I achieve this?
One way:
Add a ChangeListener to the JButton's ButtonModel
In this listener check the model's isPressed() method and turn on or off a Swing Timer depending on its state.
If you want a background process, then you can execute or cancel a SwingWorker in the same way.
An example of the former:
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ButtonPressedEg {
public static void main(String[] args) {
int timerDelay = 100;
final Timer timer = new Timer(timerDelay , new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button Pressed!");
}
});
JButton button = new JButton("Press Me!");
final ButtonModel bModel = button.getModel();
bModel.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent cEvt) {
if (bModel.isPressed() && !timer.isRunning()) {
timer.start();
} else if (!bModel.isPressed() && timer.isRunning()) {
timer.stop();
}
}
});
JPanel panel = new JPanel();
panel.add(button);
JOptionPane.showMessageDialog(null, panel);
}
}
I want to keep executing work while a button is pressed
Execute that process in another thread and then your form is not block and you can press the button to cancel or stop the execution.
see :
How to stop threads of a Java program?
Stop/cancel SwingWorker thread?
Control thread through button
You may need to use mousePressed event to start the action
And use mouseReleased event to stop the action (This is neccesary)
For more information refer here
For Android Apps
I know this question is old, but you can use:
while (yourButton.isPressed()) {
// Do Stuff
}

How to make an image gallery with java

For class I'm working on my first GUI application. It's just a simple image viewer with four buttons: Previous, Next, Stop, Play. Previous and Next work fine, but honestly I don't even know how to begin working on the slideshow part (Play & Stop). I know there's a timer class that would probably be handy for controlling the speed as the images change...but I'm not sure what kind of logic is typically used to cycle through the images. Can anyone point me in the right direction, my brain is a little fried at this point :0
I've included my code below. I'm new to this, so hopefully people won't be too critical of my technique. If it matters, I'm working in eclipse.
here's my code so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.TimerTask;
public class ImageGallery extends JFrame
{
private ImageIcon myImage1 = new ImageIcon ("Chrysanthemum.jpg");
private ImageIcon myImage2 = new ImageIcon ("Desert.jpg");
private ImageIcon myImage3 = new ImageIcon ("Jellyfish.jpg");
private ImageIcon myImage4 = new ImageIcon ("Penguins.jpg");
JPanel ImageGallery = new JPanel();
private ImageIcon[] myImages = new ImageIcon[4];
private int curImageIndex=0;
public ImageGallery ()
{
ImageGallery.add(new JLabel (myImage1));
myImages[0]=myImage1;
myImages[1]=myImage2;
myImages[2]=myImage3;
myImages[3]=myImage4;
add(ImageGallery, BorderLayout.NORTH);
JButton PREVIOUS = new JButton ("Previous");
JButton PLAY = new JButton ("Play");
JButton STOP = new JButton ("Stop");
JButton NEXT = new JButton ("Next");
JPanel Menu = new JPanel();
Menu.setLayout(new GridLayout(1,4));
Menu.add(PREVIOUS);
Menu.add(PLAY);
Menu.add(STOP);
Menu.add(NEXT);
add(Menu, BorderLayout.SOUTH);
//register listener
PreviousButtonListener PreviousButton = new PreviousButtonListener ();
PlayButtonListener PlayButton = new PlayButtonListener ();
StopButtonListener StopButton = new StopButtonListener ();
NextButtonListener NextButton = new NextButtonListener ();
//add listeners to corresponding componenets
PREVIOUS.addActionListener(PreviousButton);
PLAY.addActionListener(PlayButton);
STOP.addActionListener(StopButton);
NEXT.addActionListener(NextButton);
}
public static void main (String [] args)
{
ImageGallery frame = new ImageGallery();
frame.setSize(490,430);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
}
class PreviousButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(curImageIndex>0 && curImageIndex <= 3)
{ ImageGallery.remove(0);
curImageIndex=curImageIndex-1;
ImageIcon TheImage= myImages[curImageIndex];
ImageGallery.add(new JLabel (TheImage));
ImageGallery.validate();
ImageGallery.repaint();
}
else
{
ImageGallery.remove(0);
ImageGallery.add(new JLabel (myImage1));
curImageIndex=0;
ImageGallery.validate();
ImageGallery.repaint();
}
}
}
class PlayButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// *need help here*//
}
}
class StopButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// *need help here*//
}
}
class NextButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(curImageIndex>=0 && curImageIndex < 3)
{ ImageGallery.remove(0);
curImageIndex = curImageIndex + 1;
ImageIcon TheImage= myImages[curImageIndex];
ImageGallery.add(new JLabel (TheImage));
ImageGallery.validate();
ImageGallery.repaint();
}
else
{
ImageGallery.remove(0);
ImageGallery.add(new JLabel (myImage4));
curImageIndex=3;
ImageGallery.validate();
ImageGallery.repaint();
}
}
}
}
Why complicating simple things,
I think that this is job for CardLayout and for slideshow is there Swing Timer
put images as Icon to the JLabel
This example shows a start/stop button that controls a javax.swing.Timer. Instead of replacing the label each time, just update the label's Icon, as suggested by #mKorbel and shown here.
You need use a thread for the slideshow. You can use a flag in the run method for continue with the show or stop if this flag change, for example, a boolean var. One example you can see in http://java.sun.com/developer/technicalArticles/Threads/applet/.
These are some guidelines that might get you started:
First you will need a separate thread to control the changing images. I suggest you write a class that implements TimerTask. Override the run() method in this class. In this run method you should put the functionality to change the current image being displayed (similar to what you did in the next and previous function).
In the actionPerformed() method for the play button you will need to create an instance of a Timer class and start your timer using the scheduleAtFixedRate(TimerTask task, long delay, long period) method (other methods in this class may be used as well, scheduleAtFixedRate() seem more appropriate though).
For the stop you will then need to add enough functionality to stop the running timer using the cancel() method in the Timer class

Categories