Disable a JButton on click and re-enable it 1 second later? - java

I need to disable a JButton on on click and enable it again 2 seconds later, so for I've tried sleeping the ui thread from the event handler, but that leaves the button in a selected state where you can't read the text of the disabled button.
The code looks something like this:
JButton button = new JButton("Press me");
button.addActionListener(new ActionListener{
public void actionPerformed(ActionEvent ae) {
JButton button = ((JButton)e.getSource());
button.setEnabled(false);
button.setText("Wait a second")
button.repaint();
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
}
button.setEnabled(true);
button.setText("");
}
What happens is the button remains in a "being selected" state with no text for the 2 seconds and instantly disables and re-enables the button at the end, which isn't what I want, what I'm aiming for is the button to stay in a disabled state with text on it for two seconds and then re-enable.
What do I do?

As user2864740 indicated - "Don't use Thread.sleep on the UI thread (the UI "freezes" and does not have a chance to repaint). Use a Timer class."
Here's an example of the kind of thing he was referring to. Should be close to what you want to do:
JButton button = new JButton("Press me");
int delay = 2000; //milliseconds
Timer timer = new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
button.setEnabled(true);
button.setText("");
}
});
timer.setRepeats(false);
button.addActionListener(new ActionListener {
public void actionPerformed(ActionEvent ae) {
JButton button = ((JButton)e.getSource());
button.setEnabled(false);
button.setText("Wait a second")
timer.start();
}
}

Related

I Have A Random Colour Program And I Need It To Rapidly Switch Through Colours

I have an ActionListener for my 'Aneurysm Mode' Button but when I press it, it does nothing...
Here is the code for the ActionListener:
private class AneurysmMode implements ActionListener {
AneurysmMode () {}
#Override
public void actionPerformed(ActionEvent e) {
while (true) {
try {
Thread.sleep(100);
frame.getContentPane().setBackground(colours[(int)(Math.random()*(9)+0)]);
}
catch (InterruptedException ex) {
}
}
}
}
You're sleeping the event dispatch thread, that's a bad idea. You will be adding the new colour to the event queue, but never actioning it because your button action listener doesn't return. If you take the while loop out of the button handler it should change every time the button is pressed.
A better option would be to change the colour in a timer action event and start the timer with a button press.
Unless you are making something sophisticated such as a game where you need much control over all the rendering. If not, you can make full use of javax.swing.timer instead of implementing your own rendering loop.
You should not apply the rendering loop or sleep in the EDT. The actions within actionPerformed is usually a "one-time" action.
Your actionPerformed in the button in this case works just like an "on/off" button, hence all you need to do is to turn on/off the timer (which controls the animation) when it is clicked:
class DrawingSpace extends JPanel{
private JButton button;
private Timer timer;
private int idx;
private Color[] colors;
public DrawingSpace(){
setPreferredSize(new Dimension(200, 200));
initComponents();
add(button);
}
public void initComponents(){
idx = 0;
colors = new Color[]{Color.RED, Color.YELLOW, Color.ORANGE, Color.MAGENTA, Color.BLUE, Color.CYAN, Color.GREEN};
button = new JButton("Let the colors rock!");
timer = new Timer(100, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
//Change color every (approx) 100 milliseconds
idx = (idx + 1) % colors.length; //cycle through the colours
setBackground(colors[idx]);
}
});
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
if(!timer.isRunning())
timer.start();
else
timer.stop();
}
});
}
}
A runner class to run the code:
class RainbowRunner{
public static void main(String[] args){
// Run the GUI code on the EDT
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Rainbow Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingSpace());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
You would not want to throw the entire game loop (or whatever you call it) into your actionPerformed method. What you can do is, on every button click, trigger the timer if it is not started:
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
if(!timer.isRunning())
timer.start();
else
timer.stop();
}
});
You may consider using a javax.swing.timer instead of writing your own loop.
In your javax.swing.timer, you can have something like this:
timer = new Timer(100, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
//Change color every (approx) 100 milliseconds
idx = (idx + 1) % colours.length; //cycle through the colours
frame.setBackground(colours[idx]);
}
});

How to run method in the JFrame by clicking button in JDialog?

I have a JFrame (called FTask) with public void method. Example code:
public void clear() {
jTable1.clearSelection();
jButton1.setEnabled(false);
jButton3.setEnabled(false);
jButton2.setEnabled(false);
jTextArea1.setText(null);
}
Then, I have JDialog with a button. I want when I click the button, frame do the 'clear' method to the frame.
I've tried:
FTask ft = new FTask();
ft.clear();
But it didn't work.
I've tried:
FTask ft = new FTask();
ft.clear();
But it didn't work.
No, it wouldn't. This code is creating a new (2nd instance) of the frame that is not set visible. What you need is a reference to the original frame.
This can be fixed in a number of ways, too broad to go into here, and is Object Oriented Programming 101 that should be mastered before trying to write GUI'd apps. - which add their own complications.
You have to use actionlistener in order to run the code when the button is clicked.
JButton button = new JButton("Click me");
//Add action listener to button
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
if(e.getSource() == button){
System.out.println("You clicked the button");
//In your case:
ft.clear();
}
}
});
As #Menno said, you have to use ActionListener in order to detect Button Clicks
Here is the Java 8 Style:
JButton button = new JButton("Click me");
//Add action listener to button
button.addActionListener(
ae -> ft.clear();
);
// Add button to frame
add(button);

Multiple Actions in a JButton

In this program, we are supposed to click a button that says "Start" and then the animation will start running across the screen. After we click "Start," the button then changes to a "Pause" button where if you click it, it stops the animation and a "Resume" button appears. I am not sure how to get all three of those actions into one button. Here is the code I have so far:
JButton button = new JButton("Start");
button.addActionListener(new
ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Timer t = new Timer(100, new
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
shape.translate(x, y);
label.repaint();
}
});
t.start();
}
});
I know this isn't right. When I run the program, the animation is idle until I hit "Start" which is correct, but then every time I hit the button again, the animation speeds up which is not correct. How do I go about adding different actions to the button?
For instance after the animation is running, I want the "Pause" button to stop the Timer when it is clicked, then to resume the Timer when I hit "Resume." The code I have now creates a new Timer object every time I click it, but this seems to be the only way I get it to work. If I put anything outside the ActionListener, I get a scope error. Any suggestions?
I know this isn't right. When I run the program, the animation is idle until I hit "Start" which is correct, but then every time I hit the button again, the animation speeds up which is not correct.
This is because you're creating multiple new Timers each time you press the button. You should have a single reference to the Timer and be making decisions about what to do based on it's current state
//...
private Timer timer;
//...
JButton button = new JButton("Start");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (timer == null) {
timer = new Timer(100, new ActionListener() {
public void actionPerformed(ActionEvent event) {
shape.translate(x, y);
label.repaint();
}
});
timer.start();
button.setText("Pause");
} else if (timer.isRunning()) {
timer.stop();
button.setText("Resume");
} else {
timer.start();
button.setText("Pause");
}
}
});
but then every time I hit the button again, the animation speeds up which is not correct.
Don't keep creating a Timer in the ActionListener. Every time you click the button you start a new Timer.
Instead create the Timer in the constructor of your class. Then in the ActionListener you just start() the existing Timer.
Then the Pause and 'Resumebuttons will also just invoke thestop()andrestart()` methods on the existing Timer as well.

How to disable the process of JComponents

savebtn.setEnabled(false);
Using the above code i disable my save button.But when i click that button the save process will work. How to stop that process when clicking disabled button.
If you disable a JButton with setEnabled(false), its registered ActionListeners will not be called when you click on the button.
However if you added a MouseListener to it with addMouseListener() method, even if the button is disabled, the registered MouseListener will still be called.
You should register an ActionListener to do the job that is required when the button is pressed/clicked. That way if you disable the button, the ActionListener will not be called if the button is clicked.
See the following example: if you click on the button, it will only print "clicked" but it will not print "action performed".
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton b = new JButton("Test");
b.setEnabled(false);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("action performed");
}
});
b.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println("clicked");
}
});
f.add(b);
f.pack();
f.setVisible(true);
If you remove the b.setEnabled(false); line and you click on the button output will be :
clicked
action performed

JOptionPane : Display button "Ok" after a certain amount of time

I would like to display the button "OK" of this JOptionPane only after a certain amount of time (let's say for example 5 sec). (My aim is actually to let finish some thread work behind this other thread)
JOptionPane jop2 = new JOptionPane();
jop2.showMessageDialog(null, "Please wait 5s", "WAIT", JOptionPane.INFORMATION_MESSAGE);
I don't know at all how to do that, could you provide me some code working which will answer to this problem?
Thank you very much in advance!
There is no specific way to do this using JOptionPane. You will have to create a custom dialog and reveal the OK button after a fixed time. You could use one pass of a Swing timer.
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
button.setVisible(true);
}
};
Timer timer = new Timer(0, taskPerformer);
timer.setInitialDelay(5000);
timer.setRepeats(false);
timer.start();
It sounds like what you're looking for is a combination of the SwingWorker and the ProgressMonitor. The SwingWorker will preform your long running task (the 5 second one), and inform the user of how it's progressing using the ProgressMonitor. An example showing you how to get the two working together can be found here:
getting the cancel event of Java ProgressMonitor
Of course, if you're convinced you want to take the approach of displaying the continue button once the work is done, here's an example that should get you started in the right direction. You'll use a SwingWorker to alert your Dialog that the long running background task has completed.
import java.awt.*;
import java.awt.Dialog.ModalityType;
import java.awt.event.*;
import javax.swing.*;
public class TempProject extends Box{
public TempProject(){
super(BoxLayout.Y_AXIS);
//Contains the content of the Alert Dialog
Box info = Box.createVerticalBox();
info.add(new Label("Please wait 5 seconds"));
final JButton continueButton = new JButton("Continue");
info.add(continueButton);
//The alert to wait 5 seconds
final JDialog d = new JDialog();
d.setTitle("WAIT");
d.setModalityType(ModalityType.APPLICATION_MODAL);
d.setContentPane(info);
d.pack();
//The action of the "Continue Button"
continueButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
d.dispose();
}
});
continueButton.setVisible(false);
//Thread That Does Work
final SwingWorker sw = new SwingWorker<Integer, Integer>()
{
protected Integer doInBackground() throws Exception {
//Do long running thread work here
int i = 0;
while (i++ < 100) {
System.out.println(i);
Thread.sleep(100);
}
return null;
}
#Override
protected void done(){
// What to do when the long runnng thread is done
continueButton.setVisible(true);
}
};
//Button to start the long running task
JButton button = new JButton("Click Me");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
sw.execute();
d.setVisible(true);
}});
add(button);
}
public static void main(String args[])
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setContentPane(new TempProject());
frame.setPreferredSize(new Dimension(500, 400));
frame.pack();
frame.setVisible(true);
}
});
}
}
you could use something like this to stop the code for 5 seconds
try {
Thread.sleep(5000); // do nothing for 5000 miliseconds (5 seconds)
} catch (InterruptedException e) {
e.printStackTrace();
}

Categories

Resources