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
Related
I have a java program that load a text file as input, read its content, modify some strings and then prints the result to a textarea. Due to several seconds required by this operation i would like to show a JProgressBar during this activity in order to inform the user that the execution is in progress and when the activity is completed close the dialog containing the JprogressBar and print the results.
Here is the code:
JButton btnCaricaFile = new JButton("Load text file");
panel.add(btnCaricaFile);
btnCaricaFile.setIcon(UIManager.getIcon("FileView.directoryIcon"));
btnCaricaFile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//JFileChooser choice = null;
final JFileChooser choice = new JFileChooser(userDir +"/Desktop");
int option = choice.showOpenDialog(GUI.this);
if (option == JFileChooser.APPROVE_OPTION) {
final JDialog dialog = new JDialog(GUI.this, "In progress", true);
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(BorderLayout.CENTER, progressBar);
dialog.getContentPane().add(BorderLayout.NORTH, new JLabel("Elaborating strings..."));
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setSize(300, 75);
dialog.setLocationRelativeTo(GUI.this);
Thread t = new Thread(new Runnable() {
public void run() {
dialog.setVisible(true);
File file = choice.getSelectedFile();
lista.clear();
textArea.setText("");
lista = loadFile.openFile(file);
for(int i=0; i<lista.size(); i++) {
textArea.append(lista.get(i)+"\n");
}
dialog.setVisible(false);
}
});
t.start();
}
}
});
For this purpose i'm using a JDialog as container for the JProgressBar executed by an appropriate thread. The problem is that the progress bar is shown for an infinite time and is not printed anything to the textarea.
Could you help me to solve this?
Thanks
Yes, you're creating a background thread for your file reading, good, but you're also making Swing calls from within this same background thread, not good, and this is likely tying up the Swing event thread inappropriately. The key is to keep your threading separate -- background work goes in the background thread, and Swing work goes only in the Swing thread. Please read Lesson: Concurrency in Swing fore more on this.
Myself, I would create and use a SwingWorker<Void, String>, and use the worker's publish/process method pair to send Strings to the JTextArea safely.
For example, something like...
final JDialog dialog = new JDialog(GUI.this, "In progress", true);
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(BorderLayout.CENTER, progressBar);
dialog.getContentPane().add(BorderLayout.NORTH, new JLabel("Elaborating strings..."));
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setSize(300, 75);
dialog.setLocationRelativeTo(GUI.this);
lista.clear();
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
#Override
public Void doInBackground() throws Exception {
// all called *off* the event thread
lista = loadFile.openFile(file);
for (int i = 0; i < lista.size(); i++) {
publish(lista.get(i));
}
return null;
}
#Override
protected void process(List<String> chunks) {
// called on the event thread
for (String chunk : chunks) {
textArea.append(chunk + "\n");
}
}
// called on the event thread
public void done() {
dialog.setVisible(false);
// should call get() here to catch and handle
// any exceptions that the worker might have thrown
}
};
worker.execute();
dialog.setVisible(true); // call this last since dialog is modal
Note: code not tested nor compiled
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();
}
};
I have written the following code to generate please wait JDialog while generation of decision tree but it opens up and appears to be blank
public JDialog pleasewait()
{
JDialog dialog = new JDialog();
JLabel label = new JLabel("Please wait...");
label.setIcon(new javax.swing.ImageIcon(getClass().getResource("/decision_tree_runner/load.gif"))); // NOI18N
dialog.setBackground(Color.BLACK);
dialog.setLocationRelativeTo(null);
dialog.setTitle("Please Wait...");
dialog.add(label);
dialog.pack();
return dialog;
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
JDialog dialog = pleasewait();
dialog.repaint();
dialog.setVisible(true);
FypProject fyp_project = new FypProject();
try {fyp_project.main_fypproject();} catch (SQLException ex) {}
dialog.setVisible(false);
}
It is likely that fyp_project.main_fypproject() is a long running/blocking call, which when called from within the context of the Event Dispatching Thread, will stop it from been able to process new events, including the repaint request.
Consider using something like a SwingWorker, opening the dialog first, execute the worker and when it's done method is called, close the dialog
Take a look at Concurrency in Swing and Worker Threads and SwingWorker for more details
I think it has to do with where in the dialog the JLabel gets added. The lack of our layout manager makes this difficult.
Try adding this before you add the JLabel:
dialog.setLayout(new GridLayout());
and remove:
dialog.pack();
i did the following steps
created separate form for pleasewait
created thread for fyp_project.main_fypproject()
passed object of form to thread class
in run method setvisible() option of pleasewait to false
public class thread_for_pleasewait implements Runnable{
Thread t ;
please_wait_form pwf;
decision_tree dt;
FypProject fyp_project = new FypProject();
#Override
public void run()
{
String[] args = null;
try {
fyp_project.main_fypproject();
pwf.setVisible(false);
dt.setVisible(true);
} catch (SQLException ex) {
Logger.getLogger(thread_for_pleasewait.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void start(please_wait_form pwf,decision_tree dt)
{
t = new Thread(this);
t.start();
this.pwf=pwf;
this.dt=dt;
}
}
I am working on a project in which I would like to close a generic JOptionPane programmatically (by not physically clicking on any buttons). When a timer expires, I would like to close any possible JOptionPane that may be open and kick the user back to the login screen of my program. I can kick the user back just fine, but the JOptionPane remains unless I physically click a button on it.
I have looked on many sites with no such luck. A doClick() method call on the "Red X" of the JOptionPane does not seem possible, and using JOptionpane.getRootFrame().dispose() does not work.
Technically, you can loop through all windows of the application, check is they are of type JDialog and have a child of type JOptionPane, and dispose the dialog if so:
Action showOptionPane = new AbstractAction("show me pane!") {
#Override
public void actionPerformed(ActionEvent e) {
createCloseTimer(3).start();
JOptionPane.showMessageDialog((Component) e.getSource(), "nothing to do!");
}
private Timer createCloseTimer(int seconds) {
ActionListener close = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window[] windows = Window.getWindows();
for (Window window : windows) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
if (dialog.getContentPane().getComponentCount() == 1
&& dialog.getContentPane().getComponent(0) instanceof JOptionPane){
dialog.dispose();
}
}
}
}
};
Timer t = new Timer(seconds * 1000, close);
t.setRepeats(false);
return t;
}
};
This code gotten from
https://amp.reddit.com/r/javahelp/comments/36dv3t/how_to_close_this_joptionpane_using_code/ seems to be the best approach to me. It involves Instantiating the JOptionPane class rather that using the static helper methods to do it for you. The benefit is you have a JOptionPane object that you can dispose when you want to close the dialog.
JOptionPane jop = new JOptionPane();
jop.setMessageType(JOptionPane.PLAIN_MESSAGE);
jop.setMessage("Hello World");
JDialog dialog = jop.createDialog(null, "Message");
// Set a 2 second timer
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (Exception e) {
}
dialog.dispose();
}
}).start();
dialog.setVisible(true);
So in this chunk of code:
//Actions performed when an event occurs.
public void actionPerformed(ActionEvent event)
{
String command = event.getActionCommand();
//If btnConvertDocuments is clicked, the FileConverter method is called and the button is then disabled [so as to prevent duplicates].
if (command.equals("w"))
{
new Thread(new Runnable()
{
public void run()
{
FileConverter fc = new FileConverter();
}
}).start();
btnConvertDocuments.setEnabled(false);
//Validation message ensuring completion of the step.
JOptionPane.showMessageDialog(this, "Step 1 Complete!", "Validation", JOptionPane.INFORMATION_MESSAGE);
}
It seems like the message dialog window pop-ups way too fast, before the FileConverter method isn't even finished being called. I was wondering if the placement of JOptionPane was correct, or if there was a way to delay a message until the method finished processing?
You can use the SwingWorker.
Have a look here, java tutorial.
SwingWorker worker = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
FileConverter fc = new FileConverter();
return null;
}
#Override
public void done() {
JOptionPane.showMessageDialog(this, "Step 1 Complete!", "Validation", JOptionPane.INFORMATION_MESSAGE);
}
};
You should use a Swing Timer with a delay, instead of using your own Thread and Runnable for this.
You can use Swing timers in two ways:
To perform a task once, after a delay.
For example, the tool tip manager uses Swing timers to determine when to show a tool tip and when to hide it.
To perform a task repeatedly.
For example, you might perform animation or update a component that displays progress toward a goal.
An example from the documentation:
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
Timer myTimer = new Timer(delay, taskPerformer);
myTimer.setRepeats(false);
myTimer.start();