So in this section of code I have, I want to essentially tell the GUI to disable the button and bring up a pop-up window when no threads are running anymore (i.e. the method called has finished).
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();
if (Thread.activeCount() == 0)
{
btnConvertDocuments.setEnabled(false);
//Validation message ensuring completion of the step.
JOptionPane.showMessageDialog(this, "Step 1 Complete!", "Validation", JOptionPane.INFORMATION_MESSAGE);
}
}
Why does that if (Thread.activeCount() == 0) never seem to get called? Is that not what I want to be doing in order to accomplish my objective? Thank you in advance for any input!
There are many threads that are running when you run a Java program (for example, the main thread :) and look here) if you want to check the state of a thread, use the getState() method (just remember to assign the thread to a Thread variable:
Thread t = new Thread(new Runnable()
{
public void run()
{
FileConverter fc = new FileConverter();
}
});
t.start();
if (t.getState().equals(Thread.State.TERMINATED) ) { ... }
Looking more into your question, you could call the join method as well, as it will block the current thread until t is done (or until timeout).
that's about Concurency in Swing, better would be wrap you BackGroung Task to the SwingWorker, very nice example by #Hovercraft Full Of Eels, or by implements Executor here
Related
basically, I have this code which was initially working with console i/o now I have to connect it to UI. It may be completely wrong, I've tried multiple things although it still ends up with freezing the GUI.
I've tried to redirect console I/O to GUI scrollpane, but the GUI freezes anyway. Probably it has to do something with threads, but I have limited knowledge on it so I need the deeper explanation how to implement it in this current situation.
This is the button on GUI class containing the method that needs to change this GUI.
public class GUI {
...
btnNext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
controller.startTest(index, idUser);
}
});
}
This is the method startTest from another class which contains instance of Question class.
public int startTest() {
for (int i = 0; i < this.numberofQuestions; i++) {
Question qt = this.q[i];
qt.askQuestion(); <--- This needs to change Label in GUI
if(!qt.userAnswer()) <--- This needs to get string from TextField
decreaseScore(1);
}
return actScore();
}
askQuestion method:
public void askQuestion() {
System.out.println(getQuestion());
/* I've tried to change staticaly declared frame in GUI from there */
}
userAnswer method:
public boolean userAnswer() {
#SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
if( Objects.equals(getAnswer(),userInput) ) {
System.out.println("Correct");
return true;
}
System.out.println("False");
return false;
}
Thanks for help.
You're correct in thinking that it related to threads.
When you try executing code that will take a long time to process (eg. downloading a large file) in the swing thread, the swing thread will pause to complete execution and cause the GUI to freeze. This is solved by executing the long running code in a separate thread.
As Sergiy Medvynskyy pointed out in his comment, you need to implement the long running code in the SwingWorker class.
A good way to implement it would be this:
public class TestWorker extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
//This is where you execute the long running
//code
controller.startTest(index, idUser);
publish("Finish");
}
#Override
protected void process(List<String> chunks) {
//Called when the task has finished executing.
//This is where you can update your GUI when
//the task is complete or when you want to
//notify the user of a change.
}
}
Use TestWorker.execute() to start the worker.
This website provides a good example on how to use
the SwingWorker class.
As other answers pointed out, doing heavy work on the GUI thread will freeze the GUI. You can use a SwingWorker for that, but in many cases a simple Thread does the job:
Thread t = new Thread(){
#Override
public void run(){
// do stuff
}
};
t.start();
Or if you use Java 8+:
Thread t = new Thread(() -> {
// do stuff
});
t.start();
My problem is that I cannot figure out a way of having a thread that "on the click of a button starts, and stops on the click of another button", and then if I click the same start button a NEW thread starts that does exactly the same operation as the first. So basically just a new instance.
In my program I have a Server app that has 2 buttons and 2 text fields. After the user has entered the correct username and password the Server app opens a new ServerSocket that listens for clients that want to connect. This is done in a separate Thread to prevent the GUI from freezing. After the stop button is pressed the Thread is stopped.
How can I get my program to start a new Thread, that does the same as the first one, when I press the start button again in the GUI? Must I perhaps make use of a loop?
Server App Code:
public class Server extends JFrame implements ActionListener {
JLabel instructionsLabel;
JLabel passwordLabel;
JPasswordField passwordTF;
JButton shutdownButton;
JButton startupButton;
JLabel usernameLabel;
JTextField usernameTF;
Thread MyThread = new Thread(new ServerRunnable());
public Server() {
super("Server");
initComponents();
}
// My problem is here
public void starterMeth() {
MyThread.start();
}
public void stopMeth() {
MyThread.interrupt();
}
// in these 2 methods
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
String f = "n";
ConnectionBean cb = new ConnectionBean();
char[] a = passwordTF.getPassword();
String b = new String(a);
String inputDetails = usernameTF.getText() + b;
Iterator it = cb.getDetails().iterator();
while (it.hasNext()) {
Object next = it.next();
if (inputDetails.equals(next)) {
f = "y";
if (source == startupButton) {
if (!MyThread.isInterrupted()) {
starterMeth();
JOptionPane.showMessageDialog(null,
"Congratulations! Server started.",
"Start-up Message",
JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(null,
"Please restart the server application.",
"Start-up Message",
JOptionPane.INFORMATION_MESSAGE);
}
} else if (source == shutdownButton) {
stopMeth();
JOptionPane.showMessageDialog(null,
"Server shut-down successfully!",
"Shut-down Message",
JOptionPane.INFORMATION_MESSAGE);
}
// only resets the text fields when the correct details are entered
passwordTF.setText("");
usernameTF.setText("");
}
}
if (f.equals("n")) {
JOptionPane.showMessageDialog(null, "Invalid username or password.", "Alert", JOptionPane.WARNING_MESSAGE);
}
cb.setCloseConnection(true);
}
private void initComponents() {
}
}
My Runnable Code:
public class ServerRunnable implements Runnable {
#Override
public void run() {
try {
ServerSocket ss = new ServerSocket(7777);
while(true) {
Socket cs = ss.accept();
new ClientThread(cs).start();
}
} catch (IOException ex) {
}
}
}
Overview
Although the creation of a thread is valid in Java, it is highly discouraged for numerous reasons. The most significant one is that the creation of a thread is quite costly and resource intensive. In addition, there are much safer/efficient models implemented in the standard library that could be used to simplify the issue. In this particular scenario, I would advise against this implementation because of the nature of the operation; start-stop reoccurring. Note, a thread cannot be restarted once it has been started and the only way to stop a thread while executing is to call interrupt(). Unfortunately, interrupting a thread requires the developer to implement error handling in the run() method. Below we will see the run() method of a Runnable or a Thread implementation.
public void run() {
try {
// Your connection logic would be here
yourLogic();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // Maintain status
}
}
Lets assume you made your own thread implementation called MyThreadImpl. Below we will see how to utilize it:
public void starterMeth() {
Thread myThread = new MyThreadImpl(); // Create thread
myThread.start(); // Start execution in parallel
}
public void stopMeth() {
myThread.interrupt(); // Stop the thread
}
Alternatively if you implement your own Runnable like you are in this application, it would look like this:
public void starterMeth() {
Thread myThread = new Thread(new ServerRunnable()); // Create thread
myThread.start(); // Start execution in parallel
}
public void stopMeth() {
myThread.interrupt(); // Stop the thread
}
Although both of theses are valid, there are better approaches.
A better approach
My suggestion is to utilize the CompletableFuture class due to its robust implementation and desirable control. CompletableFutures utilize the global ForkJoinPool.common() for its threading so that the application can execute with more efficiency. In addition, you can receive the Future that is within the object for later use instead of attempting to re-create it each time. Lets investigate how this implementation would work below:
public class Server {
CompletableFuture<Void> myFuture;
...
public void starterMeth() {
myFuture = new CompletableFuture<Void>(); // Create future
myFuture.runAsync(new ServerRunnable()); // Start execution in parallel
}
public void stopMeth() {
myFuture.cancel(true); // Stop the future
}
...
}
Java does not allow to restart a Thread once it has finished executing.
Interrupting the Thread you created will simply finish its execution. The problem here is that you are using the same Thread that has finished executing (once the stop button has been clicked).
I suggest one of the following:
Improve your runnable so that when the user attempts to clicks the shutdownButton button, it stops what it was doing, and acquires some sort of semaphore to make it "sleep" until the startupButton is hit again.
(Easier) Always create a new thread on starterMeth. Don't forget to check if a Thread is running and interrupt it before starting a new thread.
I hope this helps.
hi im creating a flashing text frame by using threading handling method, here is my code:
import javax.swing.*;
public class FlashingText extends JApplet implements Runnable {
/**
*
*/
private static final long serialVersionUID = 1L;
private JLabel jlblText = new JLabel("welcome",JLabel.CENTER);
public FlashingText() {
add(jlblText);
new Thread(this).start();
}
#Override
public void run() {
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
} catch(InterruptedException ex) {
}
}
}
after i compiled and ran it, it seems the text does not flashing at all
is there anything wrong with my code?
thanks a lot!
There's a better solution, which updates the UI in Event Dispatcher Thread and does not block it.
final JLabel label = new JLabel("Some text");
final Runnable updater = new Runnable() {
#Override
public void run() {
label.setVisible(!label.isVisible());
}
};
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
SwingUtilities.invokeLater(updater);
}
}, 2, 2, TimeUnit.SECONDS);
From the code, it does not really seem that you are flashing anything. Some issues I see with your code:
If the label has no text, the getText() method will yield an empty string ("") and not null.
When updating visual components, you would need to go through the Event Dispatcher Thread (EDT). This is exposed to you through the SwingUtilities.invokeLater(Runnable runnable) class.
It is usually a bad idea to sleep() threads. If you make the changes through the EDT, you would be hanging the ED Thread which will cause the application UI to freeze, which is not desired.
You are swallowing exceptions. In your exception handling, you are not doing anything. It is considered bad practice to not handle exceptions (sometimes a simple log message will do).
According to me there is a problem in the following code block:
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
}
Because see at the first time the value is welcome, so it will enter the loop and go to else and set it null and then immediately it will check again, as there is no sleep in else so it will check again and enter the if block and set it to welcome, and this whole process will be done at a great speed so you would not be able to see the flashing effect. So I think that you should try putting a sleep at the end of the else block and see, according to me it should work then.
You should change:
else
jlblText.setText(null);
to
else{
jlblText.setText(null);
Thread.sleep(500);
}
or something like this
I have a window, with a Start- and Stop-Button. The Start-Button starts the algorithm and the stop-button should stop it. I use SwingWorker do run the algorithm in the background and normally calling worker.cancel(true) should stop the algorithm running. I also have a Label, that visualize the Status, e.g. if I press "Stop", then the Labeltext changes to "stopped", so the Problem isnt on the actionLister of the Button.
My code looks like this:
public class MainWindow extends JFrame implements ActionListener, WindowListener
{
// Some code, like generating JFrame, JButtons and other stuff not affencting the task.
Worker worker = new Worker();
public void actionPerformed(ActionEvent e)
{
boolean isStarted = false;
// Start Button
if (e.getSource() == this.buttonStart)
{
if(!isStarted)
{
System.out.println("start");
labelSuccess.setText("Mapping started!");
this.setEnabled(true);
worker.execute();
isStarted = false;
}
}
// Stop Button
if (e.getSource() == this.buttonStop)
{
labelSuccess.setText("Mapping stopped!");
worker.cancel(true);
}
}
class Worker extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
if(!isCancelled())
{
mapp();
Thread.sleep(60);
if (isCancelled()) {
System.out.println("SwingWorker - isCancelled");
}
}
return null;
}
}
At this Point, pressing the Stop-Button causes just a change of the Label-Text, but the algorithm in the background is still running. This now bothers me for quite a while and I just can't get it going.
Thanks a lot for any help, much appreciated.
edit1: I generate a new instance of worker now outside of actionPerformed, so now there is no new Worker generated on every mouse click.
Maybe if you use while instead of if on doInBackground() method of Worker class you will solve your problem. You must to put out of the while loop the mapp(), because you only want to invoke it one time. You should do something like this:
class Worker extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
mapp();
while(!isCancelled()){
Thread.sleep(60);
}
System.out.println("SwingWorker - isCancelled");
return null;
}
This link could be useful to understanding how to use SwingWorker.
EDIT:
As you can see on another questions like this or this, using SwingWorker has some problems to manage the cancel method, because this method Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason, like Oracle explains, and those "some other reasons" are discussed on the links I've posted.
You can do solve your problem using directly Threads. Your code would be something like this:
public class MainWindow extends JFrame implements ActionListener, WindowListener
{
// Some code, like generating JFrame, JButtons and other stuff not affencting the task.
final Thread th1 = new Thread(new Runnable() {
#Override
public void run() {
mapp();
}
});
public void actionPerformed(ActionEvent e)
{
boolean isStarted = false;
// Start Button
if (e.getSource() == this.buttonStart)
{
if(!isStarted)
{
System.out.println("start");
labelSuccess.setText("Mapping started!");
this.setEnabled(true);
th1.start();
isStarted = false;
}
}
// Stop Button
if (e.getSource() == this.buttonStop)
{
labelSuccess.setText("Mapping stopped!");
th1.stop();
}
}
This solutions uses the method stop(), which is deprecated, but it works. I've tried using interrupt(), but I don't know why the thread ran till finish the execution of mapp(). Obviously, using stop() is not the best method but it works stopping the mapp() execution before it finishes.
I recommend you to learn more about SwingWorker, Thread and Task to find the best solution to your problem.
Your problem is there is no loop in the worker: if you want to cancel a process using a flag, that process should check the flag from time to time, so if your method Worker.mapp() has to be stopped, check the flag there, no just before and after calling it.
My understanding is that if I start up another thread to perform some actions, I would need to SwingUtilities.invokeAndWait or SwingUtilities.invokeLater to update the GUI while I'm in said thread. Please correct me if I'm wrong.
What I'm trying to accomplish is relatively straightforward: when the user clicks submit, I want to (before performing any actions) disable the submit button, perform the action, and at the end of the action re-enable the button. My method to perform the action updates the GUI directly (displays results) when it gets the results back.
This action basically queries a server and gets some results back.
What I have so far is:
boolean isRunning = false;
synchronized handleButtonClick() {
if ( isRunning == false ) {
button.setEnabled( false );
isRunning = true;
doAction();
}
}
doAction() {
new Thread() {
try {
performAction(); // Concern A
} catch ( ... ) {
displayStackTrace( ... ); // Concern B
} finally {
SwingUtilities.invokeLater ( /* simple Runnable to enable button */ );
isRunning = false;
}
}
}
For both of my concerns above, do I would have to use SwingUtilities.invokeAndWait since they both will update the GUI? All GUI updates revolve around updating JTextPane. Do I need to in my thread check if I'm on EDT and if so I can call my code (regardless of whether it updates the GUI or not) and NOT use SwingUtilities.invokeAndWait?
EDIT: Here is what I am doing now:
handleButtonClick() {
if ( isRunning == true )
return;
disable button;
SwingWorker task = new MyTask();
task.execute();
}
...inside MyTask
doInBackground() {
return performAction();
}
done() {
result = get();
enable button;
isRunning = false;
interpret result (do most of the GUI updates here);
}
While performAction() does some GUI updates, I have wrapped those in:
if ( SwingUtil.isEDT() )
doGUIupdate()
else
SwingUtil.invokeLater( new Runnable() {
run() {
doGUIupdate();
}
} );
Hopefully this is a step in the right direction, please comment if you believe there are better ways to handle my situation.
In my opinion you should almost never use invokeAndWait(). If something is going to take awhile that will lock your UI.
Use a SwingWorker for this kind of thing. Take a look at Improve Application Performance With SwingWorker in Java SE 6.
You should consider using SwingWorker since it will not block the UI thread, whereas both SwingUtilities methods will execute on the EDT thread, thus blocking the UI.
I keep the simple Thread inside EventQueue.invokeLater(...) and that worked smoothly...
java.awt.EventQueue.invokeLater(new Runnable() {
public void run(){
new Thread(new Runnable(){
public void run(){
try{
EdgeProgress progress = EdgeProgress.getEdgeProgress();
System.out.println("now in traceProgressMonitor...");
while(true){
// here the swing update
if(monitor.getState() == ProgressMonitor.STATE_BUSY){
System.out.println(monitor.getPercentDone()/2);
progress.setProgress(monitor.getPercentDone()/2);
}else{
break;
}
Thread.sleep(5);
}
}catch(InterruptedException ie){}
}
}).start();
}
});