in my program I have to use JProgress Bar to show in real Time ,how many pixels are already encrypted ..so i was looking in internet and i found that i should use Thread , i tried but not working ,here is what I've done :
public class progress_barr extends Thread
{
public void run ()
{
JPB_crypt.setValue(prog); // prog is manipulated in showpixels function
System.err.println("progress here !");
}
}
public class calculate extends Thread
{
public void run()
{
showPixel();
}
}
than i call them later , this is how i use it
JPB_crypt.setValue(0);
appel=1; // to initiate show function
calculate calc = new calculate();
progress_barr pb = new progress_barr();
calc.start();
pb.start();
the problem still the same , my program finish data treatment than it set my jprogress to 100 % ..not in progressing but at once !
i need them to work simultaneously
Your general idea of using a thread is correct, but in order to be able to update the JProgressBar on the go with your calculation progress you need to use a SwingWorker.
The idea behind the SwingWorker is the fact that you can have methods running in the backgournd, by using the doInBackground method, which then publish your results to be used by the UI without locking it.
What you do in your bit of code is to actually have two threads that start at the same time. The first one calculates whatever is that you need to calculate and the second is supposed to update on the fly the progress bar.
This approach will not work, because each time the second thread will have to wait for the first one to end it's job in order to get the results.
You can read more about the SwingWorker here:
https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html
Related
I'm building a user-interface with Java's swing library, and I've run into a problem.
When updating a text-area in a long method, there is a pause while the method runs, and then the text area is updated all at once, instead of a little bit at a time.
I managed to fix the problem using a new thread in the following manner:
private void jButtonActionPerformed(java.awt.event.ActionEvent evt) {
Thread x = new Thread() {public void run() {
// do things that update a text area
}}; x.start();
}
This works perfectly for having the text area update in small pieces, as opposed to all at once.
However, the only problem is that this method can only be called once or Java crashes. I read that this has to do with only being able to create the thread one time. How can I modify the code to keep the desired functionality?
Any help would be greatly appreciated.
Well, I doubt you codes crashing because of the Thread creation, because each time the method is called, you're creating a new Thread (you can't restart an existing instance of a Thread that has already been started (even if it's completed or not)), the likely cause is you're getting a concurrent modification exception because Swing is not Thread safe...
Probably the easiest solution would be to use a SwingWorker which will allow you to execute your long running task in the background, but provide easy to use functionality to update the UI safely, through the publish, process and done methods.
Do prevent possible issues, you might also consider disabling the button until the load action is completed, which will prevent people from mashing the button spawning multiple background processes...
Well you can make new object of the Thread and override all the method means runnable.
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Executed..*****");
}
}).start();
try this.
Just for comparison's sake, here is an example using SwingUtilities.invokeLater. I echo MadProgrammer's advice though, learning about SwingWorker is much more beneficial in the long term and gives better variable handling.
newGame.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent arg0) {
panelList.get("newGame").setEnabled(false);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// this is where the heavy processing occurs
newGameButton();
// re-enables the button afterwards
panelList.get("newGame").setEnabled(true);
}
});
}
});
Also, once your code is working better, you can probably look into ways to optimise the speed of the update (even when dealing with Swing objects). The above call used to hang for a second or so, but I've got the delay to about 50 - 100ms or so with further work on the model :)
I've been told that I need to create a SwingWorker for a long-running directory tree walker whose "guts" are shown in pieces below. (To keep it short, I've removed lots of closing } and ) and other superfluous (to my question) stuff such as ignored catch clauses.)
When matching a given filename pattern, a filename (and other stuff) is written, by report(), to a text area:
public class TASK extends SimpleFileVisitor<Path> implements Runnable{
public static FileVisitResult disposition = FileVisitResult.CONTINUE;
private static void report(String s){
try{
Output.jTextArea1.append(s + "\n");
catch (Exception e){ aborted = true ; disposition = FileVisitResult.TERMINATE;}
public void run() {
disposition = FileVisitResult.CONTINUE;
Files.walkFileTree(p , this); // walkTreeFile calls visitFile() for each file.
public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException {
report(f1.getFileName().toString());
return disposition;
main() just creates threads for GUI and Output:
public static void main(String args[]) { // main
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
gui = new GUI();
gui.setVisible(true);
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
info = new Output();
When the "Search" button is clicked jbSearch...() makes the output window visible and instantiates TASK and the tree walk begins:
private void jbSearchActionPerformed(ActionEvent evt) { // this is in GUI
try {
TASK v = new TASK();
Thread t = new Thread(v);
t.start();
It all works fine BUT the output window flickers and looks hacked, so I need SwingWorker. But I can't say the following because TASK (or something) has to extend SimpleFileVisitor:
class TASK extends SwingWorker<List<String>, String>
So I'm looking for something to implement. My notes tell me "Because SwingWorker implements Runnable, a SwingWorker can be submitted to an Executor for execution" so I think I'm heading there next unless somebody stops me! (I've never used executors before.)
After I figure out how in involve SwingWorker, I assume I should do the following, probably in jbSearch...() in place of the 3 lines shown (just above):
TASK.execute();
I guess I have to make doInBackground() call visitFile(), which is what is applied to all the files in the walk. Is it MY responsibility to fill the array that doInBackground() returns? The Java tutorial for SwingWorker suddenly returns numbers which isn't defined anywhere to be an array or anythin else.
So I guess I have to make process() call (my) report(), which appends new info to the output window (text area). I assume that once doInBackground() fills the array of chunks, it will be easy to process them.
But where do I put get()? The Java tutorial for SwingWorker sort of suggests that get() isn't necessary, since the example writes to a text area and get() is merely used with System.out to display the same info on the console.
(EDIT) Oh yeah... What do I publish()? I guess I publish inside report().
But I'm posting anyway since I THINK the question and/or answer COULD be a valuable find for someone asking the next question about SwingWorker.
(EDIT) A big problem I think I face is that walkFileTree more or less "is" a loop, repeatedly calling visitFile() behind the scenes, ending when the tree ends or when the return value in visitFile() is set to TERMINATE. So do I just stick visitFile() in doInBackground() since it's more or less already in a loop? And then put publish() right after it?
But then how do I return an array?
Ug.
So I'm looking for something to implement. My notes tell me "Because
SwingWorker implements Runnable, a SwingWorker can be submitted to an
Executor for execution" so I think I'm heading there next unless
somebody stops me! (I've never used executors before.)
After I figure out how in involve SwingWorker, I assume I should do
the following, probably in jbSearch...() in place of the 3 lines shown
(just above):
TASK.execute();
Yes, SwingWorker#execute is the typical way to start a SwingWorker
I guess I have to make doInBackground() call visitFile(), which is
what is applied to all the files in the walk. Is it MY responsibility
to fill the array that doInBackground() returns? The Java tutorial for
SwingWorker suddenly returns numbers which isn't defined anywhere to
be an array or anythin else.
Anything you want done in the background should be called from this method.
Yes, you need to generate the result yourself. The actual value can be defined anywhere, but I personally define a local variable within the context of the doInBackground method
So I guess I have to make process() call (my) report(), which appends
new info to the output window (text area). I assume that once
doInBackground() fills the array of chunks, it will be easy to process
them.
In order for values to be processed, you need to first publish them. When these values are passed to process will depend on how intensive your background process is.
Overriding done and calling get will also allow you to access what was returned from doInBackground within the context of the EDT
But where do I put get()? The Java tutorial for SwingWorker sort of
suggests that get() isn't necessary, since the example writes to a
text area and get() is merely used with System.out to display the same
info on the console. If I don't need to call get(), maybe I'm closer
to a solution that I thought when I started this.
This will depend. Do you care about the result? If you do, I tend to call it within the done method, because, generally, I want to use the values within the EDT.
The important thing to know about get is that it is blocking, that is, it will wait until doInBackground returns
For example
So, I've been working on an app that has a Plan model with a number of different inputs and outputs, and the layout of the app has slider controls for the inputs and labels for the outputs. When an input changes, it updates the model, which then runs a calculation, and then updates the views. I didn't think there was anything wrong with this architecture at first, but even simple calculations seem to run really slowly, blocking the UI thread. Granted, I do have a somewhat complicated way of updating things:
Slider (in a viewgroup subclass) updates its value and sends a message to a delegate (which implements an interface specific to that viewgroup subclass).
Delegate (which holds the model and the control subviews) tells the Plan instance to set a new value, which triggers the plan to recalculate its outputs.
Once the plan finishes its calculations, it sends another message to the delegate, which then tells its output views to update with the new values.
I've modeled this architecture off of an iOS app that I developed which didn't seem to have as big of a problem running the calculations.
Now, I know that Android is significantly different than iOS, so I'm wondering if I'm going about this completely wrong. Is there a way to just tell these views to watch the Plan model for changes and then grab the value it's supposed to display?
Another major issue that I'm seeing here is with the slider input. If I put the model update calculations into a thread, every time the slider changes, a new thread will be created. These threads (as I've seen) will more or less finish in random order, updating the view in such a way as too make very little sense when you should see incremental changes. Is there a good way of threading calculations that are supposed to be changeable with a seekbar?
Have you looked at Observer and Observable?
Maybe your observed model can perform the update using Runnable and then notify the observer.
This is just an idea of the top of my head:
Instead of just starting a new thread for each update from the slider, you could implement some kind of Queue.
You would need a to have a Thread running, that holds the Queue.
public class QueueThread extends Thread {
private boolean running;
private ArrayDeque<Runnable> queue;
private Thread current;
public QueueThread() {
running = true;
queue = new ArrayDeque<Runnable>();
current = new Thread();
}
#Override
public void run() {
while( running ) {
if( !queue.isEmpty() && !current.isAlive() ) { //We only want to start a new thread if there is one or more in the queue AND the old task is not runnning.
current = new Thread( queue.pollFirst() );
current.start();
}
else
try {
Thread.sleep( 200 ); //We need a sleep in order to not hammer the CPU.
}
catch( InterruptedException e ) {
e.printStackTrace();
}
}
}
public void stopThread() {
running = false;
}
public void add( Runnable task ) {
queue.addLast( task ); //Here is where we add a task to the queue. The slider (or whoever posts the updates) must have a reference to this thread object.
}
}
Doing this would allow each update to finish before the next is started. I am not sure how it will do in performance. I haven't tested it or anything. It was just an idea.
I have a JFrame with a CardLayout set as its layout manager. This has two JPanel subclasses in it. One is a panel, WordsLoadingPanel, which displays the text "Loading words..." and has a JProgressBar. The other has to actually load the words. This takes a while (about 10-14 seconds for 100 words; it's a pretty selective algorithm), so I want to assure the user that the program is still working. I made the loading algorithm in the panel fire a property change with firePropertyChange(String, int, int), and the WordsLoadingPanel is catching the change just fine - I know this because I added a listener for this event to perform a println, and it works. However, when I change the println to actually changing the JProgressBar's value, it doesn't do anything. I know I'm changing the value right, because if I set the value before the algorithm starts, it works, and it works on the last iteration of the loop. I'm guessing this is because my algorithm is eating the computing power and won't let JProgressBar update.
So, my question is: How do I make my algorithm wait for Swing (would this be the AWT Dispatching Thread?) to finish updating the progress bar before continuing? I've tried:
Thread.yield in each iteration of the loop
Thread.sleep(1000L) in each iteration of the loop, in a try/catch
putting everything in the loop in a SwingUtilities.invokeLater(Runnable)
putting only the CPU-intensive algorithm in a SwingUtilities.invokeLater(Runnable)
EDIT: To further support my hypothesis of the CPU-eating algorithm (sounds like a children's story…), when I set the JProgressBar to indeterminate, it only starts moving after the algorithm finishes.
Does anyone have any suggestions?
Thanks!
To do expensive operations in background, consider using the SwingWorker class. The documentation has examples on how to use it to do tasks that interact with the user interface in a separate thread, including progress display in JProgressBars.
If you have trouble understanding how the class works, consider:
SwingWorker is a generic class that takes two parameters: T, and V
The doInBackground method returns T and is executed in a separate thread.
Since Swing may only be manipulated in the Event Dispatch Thread, you may not manipulate Swing in doInBackground.
The process method takes a List<V> as a parameter and is called asynchronously on the Event Dispatch Thread.
The publish method takes V... arguments and sends them for processing in the process method.
In conclusion:
T is the type of the result of the computation, if any.
V is the type of the data needed to manipulate the user interface.
Your algorithm should run entirely in doInBackground.
The user interface should be manipulated in the process method.
Your algorithm should use publish to send data to the process method.
OK, I've solved it. For anyone who may have a similar problem, my solution was to change the method which begun the algorithm from executing it synchonously to asynchronously (with new Thread(Runnable).start). So, my code is now
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Thread(new Runnable () {
public void run () {
window.keyboardTrainingPanel.initialize();
}
}).start();
}
});
I hope this can help someone! However, if there is a better way to do this, feel free to notify me.
I've searched for a solution for my problem all over but I cannot find anything close. Here is my problem: I have just started to learn Swing in Java and I have an application that will click randomly between a min and max amount of time. The user enters a min and max time and clicks a button which starts this code:
class CalcButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
//get data from text fields and store as integers in milliseconds.
//create a robot and random number between min and max
while(run == true){
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(num.nextInt(max-min+1)+min);
}
}
}
}
I've removed some code because it wasn't relevant to the issue.
The problem is I have another button to set the variable run to false but once the first button is clicked, I can't click the second button or the exit button at the top for that matter.
I'm sure my mistake is a very basic one but I can't see it.
Thank you for any replies that help me better understand the subject.
Edit: Changed the while loop from "while (run = true)" to "while (run == true)".
while(run == true){
"=" sets run to true
"==" compares the value of run to true
Also you can just use
while(run){
Take a look at SwingWorker. And just do while(run)
Every event will be processed by a single thread called Event Dispatch thread(EDT). If you have an infinite call inside one of the events, EDT cannot process the next event in the event queue.
UPDATE
This answer is updated, because #uckelman pointed me out that, with the condition run = true, the stop button never breaks the while loop, because it's needed to change to run = false within the loop. Then I post a simple and alternative solution to this logic problem, to schedule a task repeatedly with a timer. For details, please check this SO question.
About the events for the buttons: if you have two buttons, one to start a loop and one to end the loop, just try this code:
class CalcButtonListener implements ActionListener{
private boolean run = true;
private java.util.Timer timer = new java.util.Timer();
private JButton start_loop, end_loop;
//here the buttons initialization
#Override
public void actionPerformed(ActionEvent ae){
if(ae.getSource()==start_loop){
java.util.TimerTask task = new java.util.TimerTask() {
#Override
public void run() {
doStuff();
}
};
timer.schedule(task, java.util.Calendar.getInstance().getTime(), 500);//here the '500' means the time, 500 ms,
the task is repeatedly executed.
}
if(ae.getSource()==end_loop){
timer.cancel();//cancel the tasks scheduled
System.out.println("Task cancelled!");
}
}
private void doStuff(){
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(num.nextInt(max-min+1)+min);
}
}
Now, the task doStuff() is scheduled to be executed each 500 ms.
Other info about java.util.Timer and java.util.TimerTask.
About your problem:
The problem is I have another button to set the variable run to false
but once the first button is clicked, I can't click the second button
or the exit button at the top for that matter.
As in a previous question, and in this page, it's written this:
Swing's single-thread rule says that Swing components can only be
accessed by a single thread. This rule applies to both gets and sets,
and the single thread is known as the event-dispatch thread.
The single-thread rule is a good match for UI components because they
tend to be used in a single-threaded way anyway, with most actions
being initiated by the user. Furthermore, building thread safe
components is difficult and tedious: it's a good thing not to be doing
if it can be avoided. But for all its benefits, the single-thread rule
has far-reaching implications.
Swing components will generally not comply with the single-thread rule
unless all their events are sent and received on the event-dispatch
thread. For example, property-change events should be sent on the
event-dispatch thread, and model-change events should be received on
the event-dispatch thread.
For model-based components such as JTable and JTree, the single-thread
rule implies that the model itself can only be accessed by the
event-dispatch thread. For this reason, the model's methods must
execute quickly and should never block, or the entire user interface
will be unresponsive.
Then, if you develop your GUI using a single Thread, when a button event is executed, your GUI will freeze, waiting for the complete execution of the related button event. In your case, on a infinite loop, your GUI will always freezing.
My suggestion is to use, for your GUI, a SwingWorker, or extend the Thread class (then developing the GUI in a separate thread), or implement the Runnable interface. Another alternative is the using of a Timer from the javax.swing.Timer package.
You can read this old question of SO about SwingWorker: How do I use SwingWorker in Java?
A tutorial for SwingWorker : http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
A tutorial to make a Thread : http://docs.oracle.com/javase/tutorial/essential/concurrency/
A question about Timer: Update JPanel and attributes in a gui, with a user-specified timer?
A tutorial about Timer: http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
You should read about Swing timers:
http://java.sun.com/products/jfc/tsc/articles/timer/
That is, make your program event-driven. Swing applications already have a loop running inside them all the time, called the event loop. It doesn't help if you start another one.
Be careful about method like while(something), this could make the program frezee, i recommend you to implement events listeners to avoid this problems...
run=true;
while(run == true){
...
while (run = true) is almost certainly not what you want. What that does is assigns true to run each time the loop condition is executed, which ensures that the loop will always continue.
What you were probably trying to say was while (run == true) which only tests whether run is true. Better is just to say while (run), which does the same thing.
If you're assigning to run from a different thread, note that you ought to make run a volatile member of your class. If you're not assigning to run somewhere else, then you have a logic bug, since there's no way to break out of the loop. In that case, you need to add a test inside the loop and set run to false when you want the loop to stop. (Or, you could have while (true) and just use a break inside the loop.)