Right now I've programmed a method for use in a swing program that is supposed to slow down the speed the method it's called in is run (via thread.sleep(x) ) and instead of slowing down the speed of refresh it's just causing the whole program to hang and the screen to refresh at the end of the methods execution.
Here's my code:
public final void doBubbleSort(String numbers[], JButton numButton[]){
for (int k = 0; k < numbers.length - 1; k++){
String str1 = "";
boolean isSorted = true;
for (int i = 1; i < numbers.length - k; i++){
if (Integer.parseInt(numbers[i]) < Integer.parseInt(numbers[i - 1]) ){
try{
String tempVariable = numbers[i];
numbers[i] = numbers[i - 1];
numbers[i - 1] = tempVariable;
isSorted = false;
str1 = numButton[i].getText();
numButton[i].setText(numButton[i-1].getText());
Thread.sleep(100);
}catch(Exception e){ System.err.println("Error: " +e.getMessage()); }
numButton[i-1].setText(str1);
}
}
if (isSorted)
break;
}
}
If anyone can tell me where I should be putting thread.sleep() to make it delay the display of items being swapped I would be greatly appreciate it.
Thanks!
You should never sleep in the event dispatch thread.
Create a model, (in your case a list)
Create a view (your swing gui)
Make sure the view gets updated once the model changes (by adding a listener for instance)
Create a separate thread that updates the model regularly (using Thread.sleep if you so like)
When changing "speed" change the sleep times for the updater-thread
You may want to have a look at the Timer class (which provides a nicer interface for doing things at a regular interval) or the Swing Workers.
You cannot do animation by putting a loop in an event handler like this. You must do it by using a separate thread, either explicitly or by using the javax.swing.Timer class. If you loop and sleep on the event thread, as you're doing, then during the entire time the loop is running, the event thread is unavailable to perform its other duties, like painting the screen.
See this article for information about using the Swing timer class.
Related
I want to put a delay on a gui. I put 2 for loops, and I repaint a label, but those 2 for loops execute one after one and label is repaint just to the final.
What can I do?
for(int i=0; i<100000; i++){
System.out.println(i);
}
label.setBackground(Color.RED);
for(int i=0; i<100000; i++){
System.out.println(i);
}
label.setBackground(Color.green);
You might want to take a look at
docs.oracle.com/javase/7/docs/api/javax/swing/Timer
It's a link to using timers in Java, which helps to remove the for loops from your program.
You can use this instead:
Timer t = new Timer(2000, YourActionListener);
t.start();
}//End of method
public void paintComponent()
{
super.paintComponent(g);
if(c%2==0)
{
label.setBackground(Color.RED);
}
else
{
label.setBackground(Color.GREEN);
}
c++;
}
...
public void actionPerformed(ActionEvent) // How your YourActionListener method looks like
{
repaint();
}
There are several ways to do a delay in a Java program. Simplest option is to do
Thread.sleep(2000);
Which simply puts the current thread to sleep for 2 seconds. Depending on what you are trying to accomplish though you may need to consider some more complex options.
This option makes your program unresponsive for the sleep time. As you have a (I assume) swing application you can use a Timer instead.
I'm trying to loop trough an array of Points with a delay, but nothing happens and I don't get errors.
Here's an example of what my code looks like:
public class Class {
private Point[] points;
private int start, delay;
public Class() {
points = new Point[] {
new Point(1, 1),
new Point(2, 1),
new Point(1, 2)
};
start = System.nanoTime();
delay = 500;
}
public void update() {
for(int i = 0; i < points.length; i++) {
long elapsed = (System.nanoTime() - startT) / 1000000;
if(elapsed > delay) {
System.out.println("x: " + points[i].x);
System.out.println("y: " + points[i].y);
start = System.nanoTime();
}
}
}
}
Everything inside the update function is working except for that for loop.
edit:
It's a java Swing application with only 1 thread.
One of your problems is that you're using an if block and not a while loop. An if block just checks once, sees that the condition is false, and skips over it. A while loop will loop until the condition is false.
For most delays you could use a general purpose Timer object such as a java.util.Timer together with a java.util.TimerTask object.
for delays in a Swing GUI you would use a javax.swing.Timer
Other options for general non-Swing computing including using a while loop that contains a Thread.sleep(...) call.
Also look into using a ScheduledThreadPoolExecutor for non-Swing delays.
Edit
Regarding your edit:
edit: It's a java Swing application with only 1 thread.
Then use a javax.swing.Timer. You can find the tutorial here: Swing Timer Tutorial
And here's the Swing Concurrency Tutorial
Also have a look at the Swing Tutorial for more on Swing development.
If you need more help, then as we've already mentioned, provide more detail in your question.
To sleep for an aproximate amount of time use Thread.sleep(millis);
Do not expect accuracy to be more than 30ms.
For a program I am creating I have used the observer pattern, yet whilst my Observable sends data almost constantly, simulated with a loop here because the actual code is hooked up to a device and measures the data, my update(); method runs as it should but swing doesn't.
Swing only updates the JTextField AFTER the loop has finished, yet when I use System.out.println() it iterates nicely each update.
Observable code:
public void collectData()
{
for(int i = 0; i < 10; i++)
{
currRandom = (Math.random() * 10);
for(Observer o : observers)
{
notify(o);
}
}
}
Observer (SWING) code:
public void update()
{
jRecievedData.setText(jRecievedData.getText() + "\n" + Double.toString(PVC.pc.getCurr()));
jlAverage.setText("Average: " + PVC.getAverage());
jlMin.setText("Minimum: " + PVC.getMin());
jlMax.setText("Maximum: "+ PVC.getMax());
// setText updates slow
}
Any help would be greatly appreciated! (I have the feeling this is going to be a threading problem , but I'm not sure and if it is, I still don't know how to do that with swing)
Instead of looping through your observers explicitly, let Observable do it, as shown here.
this.setChanged();
this.notifyObservers();
Also, verify that you are not blocking the event dispatch thread. If so, consider using SwingWorker, which greatly simplifies Swing threading.
I am using java.
I have a click event that adds "squares" to a container, in a loop. I want each square to show up RIGHT when it is added. I tried running the 'adding of the squares' in a separate thread, but it is not working.
Here is some code I use for 'public class GuiController implements ActionListener, MouseListener':
#Override
public void mouseClicked(MouseEvent e)
{
//createBoardPane();
new Thread
(
new Runnable()
{
public void run()
{
showAnimation();
}
}
).start();
}
public void showAnimation()
{
for(int i = 0; i < model.getAnimationList().size(); i++)
{
String coord = model.getAnimationList().get(i);
int x = Integer.parseInt(coord.substring(0, coord.indexOf(',')));
int y = Integer.parseInt(coord.substring(coord.indexOf(',') + 1, coord.length() - 2));
boolean shouldPlacePiece = (coord.charAt(coord.length() - 1) == 'p');
if(shouldPlacePiece)
{
model.getView().getBoardPane().getComponent(x + (y * model.getBoardSize())).setBackground(Color.BLACK);
}
else
{
model.getView().getBoardPane().getComponent(x + (y * model.getBoardSize())).setBackground(Color.WHITE);
}
model.getView().getBoardPane().repaint();
long time = System.currentTimeMillis();
while((System.currentTimeMillis() - time) < 250)
{
// wait loop
}
}
}
any help is appreciated!
Creating a separate Thread to run for this longish-running task was an excellent idea - unless you want to lock-up interactions with your GUI while doing your animation.
Now, Swing GUI objects are not Thread safe (with few exceptions), so you cannot work with them from a thread other than Swing's Event Dispatch Loop's thread. So take all the GUI update code in your for-loop, and wrap it with a new Runnable (yes, another one).
Then call SwingUtilities.invokeLater(Runnable doRun) with that Runnable on each iteration of the loop.
Your GUI update code will then be scheduled to run ASAP on the Event Dispatch Loop, which will occur while your worker thread goes to sleep (do you have anything against Thread.sleep?).
Alternative: Use SwingWorker instead of Thread
SwingWorker will create and manage a new the Thread for you, and publish data that it (SwingWorker) will cause to be run on the Event Dispatch Loop's thread. You'll override doInBackground with your code. Call publish with parameters to push across into the Event Dispatch Thread. Override process with code to process those parameters and update your GUI.
On gotcha with SwingWorker is that it accumulates published events over a period of about 33 milliseconds. If you're publishing more frequent than that you may get all your events bunched together every 33 milliseconds or so. In you case, 250 milliseconds between updates shouldn't be a problem.
I want my program to start off using a countdown timer that will be displayed to the user. The only way I can think to do that is to label.setText() and Thread.sleep(). I've tried for about 20min trying to get it to work, but can't seem to crack it. Help?
Use a Swing timer. Basically you create a class that implements ActionListener, create a javax.swing.Timer, and the actionPerformed method of the ActionListener gets called at an interval you specify. In your actionPerformed method, check the time, and update the value to be displayed when appropropriate, and call repaint(). Use an interval of 0.1 second, and your countdown will be smooth and accurate enough.
I wouldn't count on the accuracy of Thread.sleep, but:
for(int i = 20; i >= 0; i--) {
label.setText(i + " seconds remaining");
Thread.sleep(1000);
}
This will, of course, block the UI thread while sleeping, so you probably need to run it on a separate thread. This means you will need something like SwingUtilities.InvokeLater to update the UI, since you are using a thread different than the UI one:
for(int i = 20; i >= 0; i--) {
SwingUtilities.InvokeLater(new Runnable() {
public void run() {
label.setText(i + " seconds remaining");
}
});
Thread.sleep(1000);
}