My program is to ping a host infinitely and display each ping result on the GUI as RED/GREEN. Here, 'res' is a label that changes its text and background based on the ping result.
The issue is that when i use while(), the GUI becomes unresponsive and the colour of the label does not change, while the ping service continues. How do i solve this issue??
while (true) {
try {
boolean status = InetAddress.getByName(host).isReachable(timeOut);
if (status == true) {
res.setText("ON");
res.setBackground(Color.GREEN);
} else {
res.setText("OFF");
res.setBackground(Color.RED);
}
} catch (IOException ex) {
}
Start by taking a look at Concurrency in Swing
Essentially, from your description, you are blocking the Event Dispatching Thread, preventing it from process new events, including paint events.
Swing is also NOT thread safe, this means you should not update the UI from outside of the context of the EDT.
In this case, you could use a SwingWorker to perform the physical "ping" from within the doInBackground method and make use of the publish/process methods to update the UI.
See Worker Threads and SwingWorker for more details
Related
I im creating a simple testing app that runs a check every hour on the selected directory/s using thread.sleep() through JFileChooser. But when i select the directory and the method runs the ui panel goes grey and the swing bits disappear. The thread seems to be putting the ui to sleep as well as the method its calling.
if (option == JFileChooser.APPROVE_OPTION) {
selectedDirectory = chooser.getSelectedFiles();
try {
while (true) {
runCheck(selectedDirectory);
Thread.sleep(1000*5);//1000 is 1 second
}
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
e1.printStackTrace();
}
}
Im looking for a way around this issue so that i can print the results of the checks being run in the ui .setText(result)
You are correct about the code putting the UI to sleep. Since sleep is called on the Event Dispatch Thread (the thread responsible for running the gui) the UI stops processing events and 'goes to sleep'.
I think what you want is a javax.swing.Timer.
Timer t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do your reoccuring task
}
});
This will cause your reoccurring task to be performed off of the EDT, and thus it wont leave your ui unresponsive.
If the code you have posted runs on the EventDispatchThread, then there is no way Swing can redraw the GUI. You're blocking (sleeping in) the thread that's supposed to handle that!
This is because you are running you check in the main GUI thread and are using an infinite loop. This check is a background task and should be executed in it's own thread so that the GUI can still receive and react to input by the user.
You also do not need to write your own implementation, Java has a Timer object.
Edit: There is also a Swing specific Timer object. This will have the action occur in the GUI thread, so if your task is long, it can cause the GUI to still lock up while the action is occurring (but not while it is waiting).
I im creating a simple testing app that runs a check every hour on the selected directory/s using thread.sleep() through JFileChooser. But when i select the directory and the method runs the ui panel goes grey and the swing bits disappear. The thread seems to be putting the ui to sleep as well as the method its calling.
if (option == JFileChooser.APPROVE_OPTION) {
selectedDirectory = chooser.getSelectedFiles();
try {
while (true) {
runCheck(selectedDirectory);
Thread.sleep(1000*5);//1000 is 1 second
}
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
e1.printStackTrace();
}
}
Im looking for a way around this issue so that i can print the results of the checks being run in the ui .setText(result)
You are correct about the code putting the UI to sleep. Since sleep is called on the Event Dispatch Thread (the thread responsible for running the gui) the UI stops processing events and 'goes to sleep'.
I think what you want is a javax.swing.Timer.
Timer t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do your reoccuring task
}
});
This will cause your reoccurring task to be performed off of the EDT, and thus it wont leave your ui unresponsive.
If the code you have posted runs on the EventDispatchThread, then there is no way Swing can redraw the GUI. You're blocking (sleeping in) the thread that's supposed to handle that!
This is because you are running you check in the main GUI thread and are using an infinite loop. This check is a background task and should be executed in it's own thread so that the GUI can still receive and react to input by the user.
You also do not need to write your own implementation, Java has a Timer object.
Edit: There is also a Swing specific Timer object. This will have the action occur in the GUI thread, so if your task is long, it can cause the GUI to still lock up while the action is occurring (but not while it is waiting).
I have a JProgressBar and want to be able to see it dynamically updated. The progress bar should be able to visibly move from one position to another, not just change without the bar visibly changing (think regular loading bars).
public static void dropHPBar(int before, int after) {
Thread.currentThread.sleep(50);
while (before > after) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
GameMain.gW.setHP(before);
b --;
}
and from GameMain.gW:
public void setHP(int x) {
hpBar.setValue(x);
}
Why is the progress bar not being visibly updated?
Calling Thread.sleep in the EDT (event dispatch thread) prevents UI updates. You need to use Swing Worker in order to archive proper concurrency.
From the Oracle website:
Swing consists of three kinds of threads:
Initial threads, the threads that execute initial application code.
The event dispatch thread, where all event-handling code is executed. Most code that interacts with the Swing framework must also
execute on this thread.
Worker threads, also known as background threads, where time-consuming background tasks are executed.
Tasks on the event dispatch thread must finish quickly; if they don't,
unhandled events back up and the user interface becomes unresponsive.
I'm currently developing an utility which is executing queries on a MySQL database and I'm currently working on the interface.
When the user clicks on the button "Connect", the status bar (JTextField) text should change to "Connecting...". This works correctly:
connectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusBar.setText("Connecting...");
}
}
});
I implemented a function to connect to a database then the "Connect" button is clicked:
connectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Class.forName("com.mysql.jdbc.Driver");
statusBar.setText("Connecting...");
connection = DriverManager.getConnection("jdbc:mysql://" + database);
}
}
});
In this case, the text of the status bar doesn't change to "Connecting..." until the connection is established.
I removed some of the code, like exception handling, for improved readability.
How can I force the text of the status bar to change before the connection is established?
Establishing a database connection should not be performed in the Event Dispatch Thread. This is preventing your component from updating. Instead, perform the task in a background thread.
If you need to report results while this action is taking place, either use the SwingWorker class, or update the component using the SwingUtilities class, in particular, invokeLater. Both of these will assure that the component(s) are updated on the EDT and that the long-running task takes place elsewhere.
For more information, please read Concurrency in Swing.
As others have mentioned the connection logic is best performed on a thread other than the Event Dispatch Thread. However, technically this is not the reason why the text field is not updated until the connection is established.
The actual reason why this occurs is that internally Swing components use a data structure to store listeners (in this case ActionListeners) whereby listeners are notified in reverse order compared to the order they were added. Hence in your example, the ActionListener that creates the connection is notified prior to the listener responsible for updating the text.
A simple fix would be to merge the two ActionListeners into a single block of code; there's no reason you need to add multiple listeners. This will of course cause your GUI to block whilst the connection attempt is being made, which is why others have advised using a mechanism such as SwingWorker to prevent this.
connectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusBar.setText("Connecting...");
new SwingWorker<Void, Void>() {
protected Void doInBackground() {
// Called on a background thread.
connectToDatabase();
return null;
}
protected void done() {
// Called on Event Dispatch thread once connect routine has completed.
try {
get(); // Propagate any exceptions back to Event Dispatch thread.
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(null,
"Failed to connect: " + ex.getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE);
}
}
}.execute();
}
});
This question is asked every two days.
If you execute code in the event dispatch thread, you block this threa, and thus prevents it from executing all its repaint actions necessary for the text to appear in the text field.
Long-running, blocking tasks should be run in a background thread, and this thread must no access the Swing components. Use SwingWorker. Its javadoc explains everything. It also has a link to the relevant section of the Swing tutorial, that you should read.
This is because you are establishing the connection in the EDT (AWT Event Dispatch Thread). While it is making the connection, nothing is done anymore to updating, handling user input and repainting the window on your screen (graphically). This means the whole application seems to be frozen until the connection is established.
So to solve this you have to make the connection in another Thread. Another dirty, not recommended approach is to force the EDT to repaint the screen after changing the text. This is the simplest way to work, but not the neat one.
This would be accomplished by calling repaint(); and then calling update(getGraphics());. But it is very dirty. I think your screen will even flicker. But this demonstrates the problem nicely. It might be interesting to test this first to see what actually happens.
I have an app and want to put the main thread to sleep for 1500ms, so I can show a ProgressDialog, but I don't know how to do it. It's possible to stop an app main thread? I can achieve the same goal using another thread right?
Stopping the main thread is usually a bad idea as it would also stop all UI interaction processing.
Try making the progress dialog modal. This will prevent the user from doing anything on your UI until the dialog is gone. I think this will achieve what you want to do and is compatible with how Android works
not a good idea to do this, but if you have to use this
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
//handle
}
Don't stop main UI thread! It will freeze UI. I can imagine that you show progress dialog during some background operation. Once this operation is complete just post something to update UI via handler.
The point of progress dialog is to interact with user while something long is executing. Otherwise you would not even need background operation and progress dialog. You would just do you operation in main UI thread and wait for UI to unfreeze.
What you're asking for should be unnecessary and as Carsten said, is a bad idea. It's a cardinal rule that you both never interrupt the UI thread and also only update elements of the UI on that thread. While a Dialog and any of it's subclasses are shown, nothing in the background will receive any input, so while it's up... though the main thread is running, nothing should be happening besides what is going on in the Dialog.
What you're probably looking to do is use something like an AsyncTask() to show your ProgressDialog, do some work, then dismiss it when that work is done.
To do something like this, you'll want to use "Runnables" along with a "Handler." As others mentioned, you don't want to stop the main UI thread. Since there is only one, you won't be showing ANY updates if you make it sleep or wait. See a small sample below of running code on another thread.
The main thing to take out of this is that sleeping the main thread means stopping any and all visual updates.
// Class Variables
private Handler mHandler;
#Override
public void onCreate(){
// Create a Handler Object
// In Layman's terms, Handlers can run processes off the main
// User interface thread.
mHandler = new Handler();
// Post a "Runnable" after a delay in milliseconds
// On a separate thread, the progressDialog_Runnable
// will call the function "createProgressDialog"
mHandler.postDelayed(progressDialog_Runnable, 250);
}
// Runnables (Process to run on separate thread)
private Runnable progressDialog_Runnable;
{
progressDialog_Runnable = new Runnable(){
#Override
public void run() {
createProgressDialog();
}
};
}
// Method you create to make the progress dialog
private void createProgressDialog(){
//... Run this code on a separate thread via Runnable
}
Sleep 10s on a thread in Kotlin
try {
Thread.sleep(10000)
} catch (e: InterruptedException) {
//handle
}