How to stop a swing timer - java

I am working on a GUI. This is the code (one ActionListener for Button and one for timer). I have a list of images to display one by one. On pressing a stop button, i am supposed to stop the timer and display the current image. On pressing the next button, i am supposed to display the next image.
This is the part of a code on Progressive Image Transmission which means displaying each of the current image in an order of clarity(resolution). This is what handler action Listener does for each image.
Problems:
On Clicking stop, the timer is not stopping, rather stop's action listener is further creating more timers i guess.(Note : Next and Stop share same Action Listeners)
On clicking next, the present running timer needs to be stopped and a fresh timer needs to be started. (Note : I used timer.restart() but it also didnt serve the purpose)
Help would be appreciated.
public void actionPerformed(ActionEvent arg0) {
int threads=0;
System.out.println("Listening : "+arg0.getActionCommand());
if(arg0.getActionCommand().equals("Send")){
stopButton.setEnabled(true);
nextButton.setEnabled(true);
}
else if(arg0.getActionCommand().equals("Stop")){
timer.stop();
saveButton.setEnabled(true);
stopButton.setEnabled(false);
}
else if(arg0.getActionCommand().equals("Next")){
stopButton.setEnabled(true);
saveButton.setEnabled(false);
timer.restart();
}
try {
image = ImageIO.read(new File(pathName[imageNo])).getScaledInstance(512,512 , BufferedImage.SCALE_SMOOTH);
}catch (IOException e) {
e.printStackTrace();
}
senderImage = new ImageIcon(image);
senderImageLabel.setIcon(senderImage);
senderFrame.setVisible(true);
ImageToMatrix(getImage(pathName[imageNo]));
Compress();
k=senderMatrix.length-1;
imageR=Decompress(k);
imageR=imageR.getScaledInstance(512, 512, BufferedImage.SCALE_SMOOTH);
receivedImage = new ImageIcon(imageR);
receiverImageLabel.setIcon(receivedImage);
receiverFrame.getContentPane().add(BorderLayout.EAST,receiverImageLabel);
receiverFrame.setVisible(true);
Handler handler = new Handler();
timer = new Timer(1000,handler);
timer.start();
sendButton.setEnabled(false);
imageNo = (imageNo+1)%5;
}
class Handler implements ActionListener{
public void actionPerformed(ActionEvent arg0) {
System.out.println("image: "+imageNo+" matrix:"+k );
k-=1;
imageR=Decompress(k);
imageR=imageR.getScaledInstance(512, 512, BufferedImage.SCALE_SMOOTH);
receivedImage = new ImageIcon(imageR);
receiverImageLabel.setIcon(receivedImage);
receiverFrame.getContentPane().add(BorderLayout.EAST,receiverImageLabel);
receiverFrame.setVisible(true);
if(k==0){
timer.stop();
}
}
}

Related

How to run two JOptionPane's with threads

I have to set two Dialogs and i want to Stop the first one and then start the second. Can anyone please help me to fix it
JOptionPane msg = new JOptionPane("your score is: " + getScore(), JOptionPane.INFORMATION_MESSAGE);
final JDialog dlg = msg.createDialog("Game Over");
dlg.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dlg.dispose();
}
}).start();
dlg.setVisible(true);
the second Dialog would be the same like
JOptionPane message = new JOptionPane("Highscore: " + getHighscore(), JOptionPane.INFORMATION_MESSAGE);
final JDialog dialog = message.createDialog("Game Over");
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
now i want to start this Dialog after the first will be closed.
Recommendations:
For the sake of Swing thread safety, use a Swing Timer rather than directly using a background thread.
Make it a non-repeating timer.
Inside the timer's ActionListener, close/dispose of the current dialog and open the 2nd.
e.g., (code not tested)
final JDialog myModalDialog = ....;
final JDialog mySecondDialog = ....;
int timerDelay = 3000;
Timer timer = new Timer(timerDelay, e -> {
myModalDialog.dispose();
mySecondDialog.setVisible(true);
});
timer.setRepeats(false);
timer.start();
myModalDialog.setVisible(true);
Alternatively: use a single dialog and swap views using a CardLayout tutorial

Disable JButton after click and enable when it done it's job

I have a JButton which has an ActionListener, which does its job as many times as I click it. Below is my code:
mouseListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) e.getSource();
source.setEnabled(false);
try {
RequestCommon.ctbCookie = jtf.getText();
System.out.println(RequestCommon.ctbCookie);
HttpURLConnection connection = HttpURLConnectionBuilder.getConnection(RequestCommon.login, RequestCommon.getCtb888Headers());
String connectionOuput = HttpURLConnectionBuilder.getConnectionOuput(connection);
System.out.println(connectionOuput);
new Player(new BufferedInputStream(new FileInputStream(new File("sounds/8.mp3")))).play();
} catch (IOException e1) {
e1.printStackTrace();
} catch (JavaLayerException e1) {
e1.printStackTrace();
}
source.setEnabled(true);
}
}
jb1.addActionListener(mouseListener);
I want it so that no matter how many times I click while the job is running it won't execute again. When the job is done, if I click again, the job will run again. I don't know how to do that, please tell me if you know, thanks!
Long running code should NOT execute on the Event Dispatch Thread (EDT). You need to start a separate Thread to do you HTTP request.
The easiest way to do this is to use a SwingWorker. You can disable the button before you start the worker and then the worker has a done() method that is invoked and you can enable the button.
Read the section from the Swing tutorial on Concurrency in Swing for more information about the EDT and a working example of a Swing worker.
Edit:
People seem confused about event handling. The listeners for an event are invoked before the next event is handled. So in the case of "double clicking" on the button. The button is disable on the first click and the long running task is started. The second click is then received on the disable button so the ActionListener is not invoked.
Here is some old code I have lying around which was written before a SwingWorker existed. The basic logic for the "Start in New Thread" button is:
disable the button so it can't be click while processing is happening
simulate a long running task by looping 10 times and sleeping
enable the button so the task can be done again
Here is the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*
* A couple of notes about long running tasks and GUI updates:
*
* 1) all GUI painting should be done in the event thread
* 2) GUI painting is not done until the event thread processing is done
*
* This means that long running code (database access, file processing ...)
* should not be done in the event thread. A new thread can be created for
* these tasks.
*
* Most Swing methods are not thread safe. If the long running task needs
* to update the GUI for any reason then the SwingUtilities class
* should be used to add code to the event thread.
*
* See the Swing tutorial on "Using Threads" for more information
* http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
*/
public class InvokeLaterTest extends JFrame
implements ActionListener, Runnable
{
JLabel status;
JButton eventThread;
JButton newThread;
JButton stop;
Thread thread;
int i;
boolean stopProcessing;
public InvokeLaterTest()
{
status = new JLabel( "Ready to Process:" );
status.setHorizontalAlignment( JLabel.CENTER );
getContentPane().add(status, BorderLayout.NORTH);
eventThread = new JButton( "Start in Event Thread" );
eventThread.addActionListener( this );
getContentPane().add(eventThread, BorderLayout.WEST);
newThread = new JButton( "Start in New Thread" );
newThread.addActionListener( this );
getContentPane().add(newThread, BorderLayout.EAST);
stop = new JButton( "Stop Processing" );
stop.addActionListener( this );
getContentPane().add(stop, BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent e)
{
// Code is executing in Event thread so label will not be updated
// and the Stop button will not be enabled.
if (e.getSource() == eventThread)
{
stopProcessing = false;
run();
}
// Code is executing in a new thread so label will be updated
else if (e.getSource() == newThread)
{
stopProcessing = false;
thread = new Thread( this );
thread.start();
}
else
{
stopProcessing = true;
status.setText("Processing Stopped");
setButtons( true );
}
}
public void run()
{
setButtons( false );
for (i = 1; i < 10; i++)
{
if ( stopProcessing ) return;
System.out.println("ProcessingFile: " + i);
// SwingUtilities makes sure code is executed in the event thread.
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
status.setText("Processing File: " + i);
status.paintImmediately(status.getBounds());
}
});
// simulate log running task
try { Thread.sleep(1000); }
catch (Exception e) {}
}
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
status.setText("Finished Processing");
setButtons( true );
}
});
}
private void setButtons(boolean value)
{
eventThread.setEnabled( value );
newThread.setEnabled( value );
}
public static void main(String[] args)
{
JFrame frame = new InvokeLaterTest();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.show();
}
}
A SwingWorker is similar to the above logic but:
you need to disable the button outside the SwingWorker
the worker will create the Thread for you and execute the code
when the worker is finished the done() method of the worker is invoked so you can enable the button.
You should use if and check if the button is enabled before executing your code.
JButton source = (JButton) e.getSource();
if(source.isEnabled()) {
.
.
.
execute your code
JButton source = (JButton) e.getSource();
if (source.isEnabled()) {
Executors.newSingleThreadScheduledExecutor().execute(() -> {
source.setEnabled(false);
--your code here--
source.setEnabled(true);
}
);
}
};
Added a completedTime variable to hold the timestamp as when the action is complete, and every event has the time when it is generated, compare and return if it is less than the completed time
long completedTime;
mouseListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) e.getSource();
long timeStamp = e.getWhen();
if (timeStamp < completedTime) {
System.out.println("returned");
return;
}
// source.setEnabled(false);
try {
RequestCommon.ctbCookie = jtf.getText();
System.out.println( RequestCommon.ctbCookie );
HttpURLConnection connection = HttpURLConnectionBuilder.getConnection(RequestCommon.login, RequestCommon.getCtb888Headers());
String connectionOuput = HttpURLConnectionBuilder.getConnectionOuput(connection);
System.out.println(connectionOuput);
new Player(new BufferedInputStream(new FileInputStream(new File("sounds/8.mp3")))).play();
} catch (IOException e1) {
e1.printStackTrace();
} catch (JavaLayerException e1) {
e1.printStackTrace();
}
// source.setEnabled(true);
completedTime = System.currentTimeMillis();
}
};

Timer doesn't work when another button is pressed (applet)

I'm making an applet which has two buttons: step back and step forward.
I have the same timer in every button to execute an animation. If I push step forward it works fine, and the animation runs, but if i push step back, the animation doesn't run or is bad runned (in a wrong position and velocity).
I guess the problem is the timer doesn't stop correctly and is running when start the timer again, but I donĀ“t know how to solve it.
This is the code of the step forward button:
//Code of the button "Paso a Paso"
this.botonPasoAPaso = new JButton("Paso a paso");
this.botonPasoAPaso.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//Avoid timer to accelerate
if (timer != null && timer.isRunning()) {
timer.stop();
}
//Code of the timer, makes an animation
timer = new Timer(35, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (pasoAPaso <= listaPaquetes.size()) {
Paquete p = listaPaquetes.get(pasoAPaso);
p.animar();
panelGrafo.removeAll();
panelGrafo.updateUI();
panelGrafo.setPaquete(p);
panelGrafo.setAnimar(true);
panelGrafo.repaint();
}
}
});
timer.start();
pasoAPaso++;
}
});
This is the code of the step back button:
this.botonAtras.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (timer != null && timer.isRunning()) {
timer.stop();
}
timer = new Timer(35, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (pasoAPaso < listaPaquetes.size() && pasoAPaso>=0) {
Paquete p = listaPaquetes.get(pasoAPaso);
p.animar();
panelGrafo.removeAll();
panelGrafo.updateUI();
panelGrafo.setPaquete(p);
panelGrafo.setPasoAPaso(pasoAPaso);
panelGrafo.setAnimar(true);
panelGrafo.repaint();
//Actualizar matriz del render para pintar celdas
RenderTabla.matrizTotal = new Cuadrado[pasos.get(pasoAPaso).length][pasos.get(pasoAPaso)[0].length];
RenderTabla.matrizTotal = pasos.get(pasoAPaso);
tabla.introducirDatos(pasos.get(pasoAPaso),false);
}
}
});
timer.start();
pasoAPaso--;
}
});
This is a video of the applet to see what's happening
If you see the video, when I click the "Paso a Paso" (Step forward) button, a truck is animated, but when I click the "rewind" (Step back) button, it doesn't work (appears a truck but is not correctly animated), and if i click again nothing happens.
Thanks.

Swing: Enabling Buttons With Delay

private void OptionsActionPerformed(java.awt.event.ActionEvent evt)
{
// After clicking on button X, I want 4 other buttons to show up
// in a sequential order
ButtonTrue();
}
public void ButtonTrue()
{
Audio_Options.setVisible(true);
letsSleep();
Control_Options.setVisible(true);
letsSleep();
Display_Options.setVisible(true);
letsSleep();
Network_Options.setVisible(true);
}
public void letsSleep()
{
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(MainMenu.class.getName()).log(Level.SEVERE, null, ex);
}
}
I have 4 buttons. I want them to appear in a sequential order such as :
Button1 - 10seconds - Button2 - 10 seconds - Button3 - 10seconds - Button 4
Problem: Whenever I call the function "ButtonTrue()", they all appear together after waiting 30 seconds. What can cause this problem to occur?
don't use Thread.sleep(int) for Swing JComponent, because blocking current EDT
you have look at Swing Timer
You should use different Threads for this:
javax.swing.Timer timer = new Timer(10000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Update the progress bar...
Control_Options.setVisible(true);
timer.stop();
}
});
timer.start();
Your buttons have to be final to be in scope for the anonymous ActionListener.
I think the problem is that all setVisble invocations are within one thread, which isn't EventDispatchThread. You could try calling:
if(EventQueue.isDispatchThread()) {
ButtonTrue();
} else {
EventQueue.invokeAndWait(new Runnable() {
ButtonTrue();
});
}

Java: Double-Click a JSlider to Reset

I have a JSlider that sets the speed of my metronome, from 40 - 200, where 120 is the default, in the middle.
When the user clicks the metronome button, the metronome plays at the speed displayed on the JSlider - the user drags the slider to the right, the speed of the metronome increases, and it decreases if they slide it to the left.
How do I add functionality so that if the user double-clicks on the JSlider button, it defaults back to 120 - in the middle?
Here is my code:
public Metronome() {
tempoChooser = new JSlider();
metronomeButton = new JToggleButton();
JLabel metText = new JLabel("Metronome:");
add(metText);
...
tempoChooser.setMaximum(200);
tempoChooser.setMinimum(40);
tempoChooser.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
tempoChooserStateChanged(evt);
}
});
add(tempoChooser);
...
}
private void tempoChooserStateChanged(javax.swing.event.ChangeEvent evt) {
final int tempo = tempoChooser.getValue();
if (((JSlider) evt.getSource()).getValueIsAdjusting()) {
setMetronomeButtonText(tempo);
} else {
processTempoChange(tempo);
}
}
thanks in advance!
This should help you out: http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
You need to read up on that and implement MouseListener. You can use int getClickCount() to count how many times the user has clicked, which will help you read double clicks.
Hope this helps!
Even though I dont see a question, my gues is you are looking for MouseListener.
Not simple job, you have to add javax.swing.Timer and listening if during fixed period Mouse cliked once or twice times, for example
I recently wrote something similar so I could differentiate between single and double left mouse-button clicks:
private Timer timer;
#Override
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1){
if (timer == null) {
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() { // timer expired before another click received, therefore = single click
this.cancel();
timer = null;
/* single-click actions in here */
}
}, (Integer) Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval"));
}
else { // received another click before previous click (timer) expired, therefore = double click
timer.cancel();
timer = null;
/* double-click actions in here */
}
}
}

Categories