I need to update jProgressBar in method which read from file and do some operations.
I tried to update progress bar by this method:
public void progressUpdate(int percent) {
System.out.println("Update = "+percent);
synchronized (jMainProgressBar) {
jMainProgressBar.setValue(percent);
}
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
jMainProgressBar.updateUI();
jMainProgressBar.repaint();
}
});
}
how ever this works only then when method is done. But if i continuously updating by this method then nothing happens.
Maybe some know how to improve this method?
It also would be nice for more suggestion Worker thread and else.
You probably want to do
public void progressUpdate(final int percent) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jMainProgressBar.setValue(percent);
}
});
}
Don't use Thread. Use Timer. Refer the following:
JProgressBar in Napkin look and feel is not working
How to Use Progress Bars
http://www.roseindia.net/java/example/java/swing/SwingProgressBar.shtml
Read Concurrency in Swing for more information
Based on the comments you provided (but not from the question!) you are performing heavy work on the Event Dispatch Thread (EDT). This blocks that thread and avoids any scheduled repaints to be performed. That is why you only see the update of your JProgressBar after the work is finished, as that is the moment the EDT becomes available to perform the repaint.
The solution is already provided in the links posted by others but it basically comes down to:
perform the work on a worker thread
update the progress on the JProgressBar on the EDT
The two most common ways to achieve this are using a SwingWorker or using SwingUtilities.invokeLater from the worker thread.
All relevant links can be found in the answer of Yohan Weerasinghe
Check this out
Timer barTimer;
barTimer=new Timer(100,new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
barvalue++;
if(barvalue>jProgressBar1.getMaximum())
{
/*
* To stop progress bar when it reaches 100 just write barTime.stop()
*/
barTimer.stop();
barvalue=0;
}
else
{
int a=(int)jProgressBar1.getPercentComplete();
jProgressBar1.setStringPainted(true);
jProgressBar1.setValue(barvalue);
}
}
});
barTimer.start();
Check the code at this link
http://java23s.blogspot.in/2015/10/how-to-implement-progress-bar-in-java.html
Related
I have something I can't understand: my Swing GUI contains a 'play' and 'pause' button. I have also a static variable that defines 'ON' and 'OFF' states. (The main program generates the GUI).
By cliking on 'play' I change the state of my static variable to 'ON' and I launch a time-consuming process in a thread that also modifies the GUI. As long as the static variable is 'ON' loops in the same process. Clicking on 'pause' would change the static variable to OFF.
But by clicking on 'play' the GUI is freezing and consequently:
The GUI doesn't update
The process can't be 'paused' with my 'pause' button.
I have heard about EDT and SwingWorker but I you have a simple way to do it I take it.
Thank you for your help and forgive my bad english...
The problem is that you're doing the intensive, time-consuming work on the same thread responsible for updating the GUI. SwingWorker allows you to move time-consuming tasks to a separate thread of execution, thereby leaving the UI thread to do its thing uninhibited.
However, it does add a further complication: affinity. Calling methods on UI components generally requires that you do so from the UI thread. Therefore, you need to use special functionality to get back to the UI thread from the worker thread. SwingWorker also gives you this ability.
I suggest you read through this documentation.
You need to read Concurrency in Swing to understand how the EDT and SwingWorkers operate.
All GUI updates are executed on the EDT so when you click a GUI component any method that this calls will be executed on the EDT. If this is a time consuming process then this will block the EDT from executing any futher GUI updates. Hence your GUI is freezing and you can't click the pause button.
You need to use SwingWorker to execute the time consuming process on another thread. The link I provided above details how to do this.
You should not start long-running processes in Swing’s event handler because it will freeze your GUI, you know that now. :) Start it in a new thread. You only need to use a SwingWorker if you’re planning on manipulating the GUI from the worker thread (because Swing is not thread-safe).
This is a pretty straightforward reason: while Java is working on your time-consuming process, it isn't able to update the GUI. Solution: run the time-consuming process in a separate thread. There are a bunch of ways to program that, and it would probably depend somewhat on how your program is written.
The event dispatch thread (EDT) is the only thread in which it's safe to read or update the GUI.
The pause button should be setting the on/off variable in the event dispatch thread.
The time-consuming operation, and the loop, should not be in the EDT. (The loop should also not be running continuously doing nothing but check the variable, or it can easily eat all your CPU. If it has nothing else to do it should check, and then call Thread.sleep() for some length of time (say 100ms).)
If you can prove that the on/off variable is being set to OFF, but that nonetheless it's always read as ON, it may be that the variable's value is not being copied from the EDT to the worker thread. Make it volatile, or synchronize access to it, or use an AtomicReference, or read it in the EDT using SwingUtilities.invokeAndWait().
SwingWorker probably is the simplest way to go, here. Implement your time-consuming operation, and the on/off check, in the doInBackground() method, and your GUI update in the done() method.
public enum State {
RUNNING, STOPPED
}
public class ThreadSafeStateModel {
private State state = State.STOPPED;
public synchronized void stop() {
state = State.STOPPED;
}
public synchronized void start() {
state = State.RUNNING;
}
public boolean isRunning() {
return state == State.RUNNING;
}
}
public class ExpensiveProcessWorker extends SwingWorker<Void, Void> {
private final ThreadSafeStateModel model;
public ExpensiveProcessWorker(ThreadSafeStateModel model) {
this.model = model;
}
#Override // Runs in background
protected Void doInBackground() throws Exception {
while (model.isRunning()) {
// do one iteration of something expensive
}
return null;
}
#Override // Runs in event dispatch thread
protected void done() {
// Update the GUI
}
}
public class StopButton extends JButton {
public StopButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Stop") {
#Override
public void actionPerformed(ActionEvent e) {
model.stop();
}
});
}
}
public class StartButton extends JButton {
public StartButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Start") {
#Override
public void actionPerformed(ActionEvent e) {
model.start();
new ExpensiveProcessWorker(model).execute();
}
});
}
}
(A lot could be done to clean this up depending on the real application, but you get the idea.)
#Override
public void actionPerformed(ActionEvent e) {
new Thread() {
public void run() {
//your code which runs on click event
}
}.start();
}
I am having a problem writing/updating the textarea. I am getting a value from the readtemp function, and i can see the result after calling the system out function, but nothing appears in the Textarea. What could be the problem?
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
URL temp;
try
{
temp = new URL("http://192.168.1.25/status.xml");
while (true)
{
System.out.println("Homerseklet: " + readtemp(temp));
jTextArea1.append(readtemp(temp));
}
}
catch (MalformedURLException ex)
{
Logger.getLogger(Download.class.getName()).log(Level.SEVERE, null, ex);
}
}
Correction: This won't help since the infinite loop will still block the EDT forever... Nevermind!
Your while loop is a really bad idea, but if you insist, you can at least give the EDT a chance to update the UI by dispatching your append asynchronously:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jTextArea1.append(readtemp(temp));
}
});
Are you doing IO and graphics in separate threads as it's supposed to be done? You should only do updating UI in the event dispatch thread, so when retrieving results from external place has completed you submit the update to event dispatch thread.
The problem exists because of the infinite loop while (true). Because the function jButton1ActionPerformed never ends, Swing has no chance to rerender the jTextArea1 component (I assume that this method is called in AWT Thread).
As mentioned in the previous answers it's a bad idea to handle long-running operations inside the swing thread. As a solution i'd replace your "textfield.append()"- Line with the following code snippet:
Java 8 way:
SwingUtilities.invokeLater(() -> jTextArea1.append(readtemp(temp)));
Pre-Java 8:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jTextArea1.append(readtemp(temp));
}
});
Source and some explanation: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
I am running out of ideas how to make my progress bar responsive during performing RMI connection, so I have decided to ask You for help.
Here's the code :
Thread performLogin = new Thread(new Runnable()
{
#Override
public void run()
{
LoginResult = TryLogin();
}
});
performLogin.start();
WaiterFrame.setVisible(true);
SetProgressDialog();
try
{
performLogin.join();
}
catch(InterruptedException exc)
{
System.err.println(exc.getLocalizedMessage());
}
if (LoginResult)
{ ... }
WaiterFrame.setVisible(false);
this.dispose();
Progress bar is unresponsive - does not animate as it should while performing performLogin thread. I was trying to run progress bar frame on the other thread too, but result was the same (as well as using Eventqueue.invokelater()).
The likely cause is performLogin.join(); is blocking the Event Dispatching Thread, making the UI non-responsive.
Two things to remember with Swing (and most GUI frameworks);
It is single threaded, meaning if your block the EDT for any reason, it will no longer able to process new events or perform repaints
It's not thread safe, so you should never modify the state of the UI from outside the context of the EDT.
You could use a SwingWorker, which would allow you to run your long running process in a background thread but provides a number of mechanism through which you can send updates back to the EDT safely.
See Worker Threads and SwingWorker for more details and Issues with SwingWorker and JProgressBar for an example
If you're using Java 8 you could try something like this:
CompletableFuture<LoginResult> loginResult = CompletableFuture.supplyAsync(this::tryLogin);
WaiterFrame.setVisible(true);
setProgressDialog();
loginResult.thenAccept(lr -> {
//do your thing
WaiterFrame.setVisible(false);
})
There are other options to "thenAccept" depending on what you need to do. "thenAccept" only consumes the the content of the Future.
The same could be accomplished using Guava's ListenableFuture and Executors if Java 8 is not an option.
Thank You very much MadProgrammer! Progress bar works as intended with SwingWorker usage. I'm posting code if someone would encourage same problem in future :
PerformLogin = new SwingWorker<Boolean, Object>()
{
#Override
protected Boolean doInBackground() throws Exception
{
LoginResult = TryLogin();
if (LoginResult)
{
MainF = new MainFrame();
MainF.Connection = DataEntry.TestConnection;
MainF.prepareFormToShow();
}
return LoginResult;
}
#Override
protected void done()
{
if (LoginResult == true)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
MainF.setVisible(true);
WaiterFrame.setVisible(false);
}
});
}
else
{
setVisible(true);
this.cancel(true);
JOptionPane.showMessageDialog(null, "Wrong adress!",
"Błąd",JOptionPane.WARNING_MESSAGE);
}
}
and
WaiterFrame.setVisible(true);
PerformLogin.execute();
in the main thread
I'm trying to update the tab being displayed, however it seems to wait until the end of the method and then update. Is there a way to make the tab being displayed update immediately?
Here is an example of the code where I'm having this issue:
private static void someButtonMethod()
{
Button = new JButton("My Button");
Button(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
tabs.setSelectedIndex(1);
// Do some other things (In my case run a program that takes several seconds to run).
runProgram();
}
});
}
The reason for this is that the method is being executed in the Event Dispatch thread, and any repaint operations will also occur in this thread. One "solution" is to update the tab index and then schedule the remaining work to be invoked later on the EDT; this should cause the tab state to be updated immediately; e.g.
public void actionPerformed(ActionEvent evt) {
tab.setSelectedIndex(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Do remaining work.
}
});
}
EDIT
Per your comment below an example of how to invoke a SwingWorker in order to call your runProgram method would look something like this:
// Typed using Void because runProgram() has no return value.
new SwingWorker<Void, Void>() {
protectedVoid doInBackground() {
runProgram();
return null; // runProgram() doesn't return anything so return null.
}
protected void done() {
// Called on the EDT when the background computation has completed.
// Could insert code to update UI here.
}
}.execute()
However, I sense a bigger problem here: The fact that you are seeing a significant delay in updating the tab makes me think you are performing long running calculations on the EDT. If this is the case you should consider performing this work on a background thread. Take a look at the SwingWorker class.
So my program has multiple classes and after one of them has run, it'd like it so it appends the text area in the main class GUI with a 'finished' message
ta.append("Search Complete\n");
and this is the code that needs to complete
statCl.addActionListener(new ActionListener(){
public void actionPerformed (ActionEvent e) {
try {
ta.append("Searching...\n");
task.execute();
} catch (Exception IOE) {}
}
});
So it is in the class where task where actual code runs.
Any advice or help would be amazing, thanks.
If the task.execute() method doesn't start launch an operation in another thread, then the GUI will be freezed, and nothing will apear in the text area until the operation is finished. So you might just have
ta.append("Searching...\n");
task.execute();
ta.append("Finished");
If the operation is launched in a new thread, then this thread should append in the text area, but it should make sure this append is done in the event dispatch thread (EDT). Your code could thus look like this :
public class Task {
private JTextArea ta;
public Task(JTextArea ta) {
this.ta = ta;
}
public void execute() {
Thread t = new Thread(new Runnable() {
// perform the long operation
// at the end, update the text area, in the EDT
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ta.append("finished");
}
});
}
t.start();
}
}
You might also look at SwingWorker, which is designed just for that (and other things like progress update). There is a code example in its class javadoc which does just what you're trying to do.
You should not be performing long-running task on EDT (event dispatching thread):
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
Swing does all it's work on EDT, so you should not block EDT, e.g. run intensive tasks on it. Note: all event handlers are executed on EDT.
So there are two challenges:
Run intensive tasks in a background thread.
Update GUI, which must be done on EDT.
Use SwingWorker to solve this two issues.