sleep pauses whole Thread - java

I know my code isnt like written following the java conventions, but its just a little test...
Ive got a JFrame in my class MainNF. This JFrame should show up and then disappear for a amount of time, which is entered in the JTextField jtf, while another frame, the NFrame frameZero, appears. After that, it should come up again and the frameZero should disappear.
So I just need code that pauses my method for an amount of time.
My Problem: If tried it with Thread.sleep(), but the problem here is the whole Thread then sleeps, so the NFrame frameZero doesnt do anything at this time.
I also tried it with the wait() method, this didnt work either.
My Code:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class MainNF{
public static void main(String[]args){
MainNF m=new MainNF();
}
JTextField jtf;
JFrame j;
JPanel acd;
JPanel [] eingabe;
JButton play;
int letzterScore;
public MainNF(){
j=new JFrame("Menue");
acd=new JPanel();
letzterScore=0;
acd.add(new JLabel("Letzter Score: "+letzterScore));
j.add(acd);
eingabe=new JPanel[2];
eingabe[0]=new JPanel();
eingabe[1]=new JPanel();
eingabe[1].setLayout(new BoxLayout(eingabe[1], BoxLayout.Y_AXIS));
eingabe[1].add(new JLabel("Sekunden fuer das naechste Spiel"));
jtf=new JTextField();
eingabe[1].add(jtf);
eingabe[0].setLayout(new BoxLayout(eingabe[0], BoxLayout.X_AXIS));
eingabe[0].add(eingabe[1]);
play=new JButton("Los!");
play.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){
j.setVisible(false);
letzterScore=play(getPlaytime());
j.setVisible(true);
}});
eingabe[0].add(play);
j.add(eingabe[0]);
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.setBounds(200, 200, 400, 400);
j.setVisible(true);
}
public int play(){
NFrame frameZero=new NFrame();
try{
Thread.sleep(getPlaytime());
}
catch(InterruptedException e){}
frameZero.setAllInvisible();
return frameZero.amount();
}
public int getPlaytime(){
return Integer.parseInt(jtf.getText());
}
}
Last I tried it with a timer, but that didnt pause anything at all:
public int play(){
NFrame frameZero=new NFrame();
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
}};
Timer t = new Timer(getPlaytime(), taskPerformer);
t.setRepeats(false);
t.start();
frameZero.setAllInvisible();
return frameZero.amount();
}
So I havent any clue what to do...
...would love you if you could help me <3

public int play() is been called from within the context of the Event Dispatching Thread, which is preventing it from, amongst other things, process repaint requests and new events.
Use a Swing Timer instead, see How to use Swing Timers for more details
You might also consider having a look at Concurrency in Swing and The Use of Multiple JFrames, Good/Bad Practice?

Related

Negative coordinates of JPanels (and lack of cooperation with Timer)

Please note that this is a more theoretical question about problems with this approach, as I'm trying to understand the underlying mechanics - genuine curiosity. For the actual implementation I'm likely to use something different.
Say we have the following frame with a split pane. The right hand side of the split pane has a button to slide out a panel on the left and show another one in its place (here I'm using overlay layout to make it look smoother). The code is as follows:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.OverlayLayout;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Main {
JPanel panel;
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
public void makeUI() {
panel = new JPanel();
panel.setBackground(Color.RED);
panel.setLocation(0,0);
JPanel panel3 = new JPanel();
panel3.setBackground(Color.BLUE);
panel3.setMinimumSize(new Dimension(100,400));
JPanel panelContainer = new JPanel();
panelContainer.setLayout(new OverlayLayout(panelContainer));
panelContainer.add(panel);
panelContainer.add(panel3);
JButton button = new JButton("slide out");
// Slide out the red panel to reveal blue
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
((JButton) e.getSource()).setEnabled(false);
new Timer(1, new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.setLocation(panel.getX() - 1, 0);
if (panel.getX() + panel.getWidth() == 0) {
((Timer) e.getSource()).stop();
panel.setVisible(false);
System.out.println("Timer stopped");
}
}
}).start();
}
});
JFrame frame = new JFrame("Sliding Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setLayout(null);
splitPane.setDividerLocation(100);
splitPane.setLeftComponent(panelContainer);
JPanel panel2 = new JPanel();
panel2.add(button);
// panel2.add(button2);
panel2.setMinimumSize(new Dimension(200,400));
splitPane.setRightComponent(panel2);
frame.setContentPane(splitPane);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main().makeUI();
}
});
}
}
Now if I add a button that reverses the animation, by setting location to (-panel.getWidth(), 0) and then increase the x coordinate, this fails. In theory the code is the same, with the only differences being in the start position, end position, and increments. However it does no longer work.
JButton button2 = new JButton("slide in");
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
((JButton) e.getSource()).setEnabled(false);
panel.setVisible(true);
panel.setLocation(-panel.getWidth(),0);
System.out.println(panel.getX()); // gives -99, which is about right
new Timer(1, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(panel.getX()); // starts from 0
panel.setLocation(panel.getX() + 1, 0);
System.out.println(panel.getX()); // keeps increasing until forcibly stopped
if (panel.getX() == 0) {
((Timer) e.getSource()).stop();
System.out.println("Timer stopped");
}
}
}).start();
}
});
More precisely the problem lies in the new Timer(...) line. As per console logging, setting location puts the X coordinate at -99, but two lines later it's at 0, and when increments occur, it goes on to infinity.
Perhaps I am misunderstanding how timers work, however after reading the documentation on it and JPanels, I still don't see why such an approach would not work. Not to mention that there is very little on negative coordinates of JPanels to begin with.
Thank you in advance for all the explanations!
EDIT (27.07.2016)
#camickr 's answer makes it work, however I still don't undersand it, although it helped me narrow the question a little:
Why is the layout re-done after setting the location to negative? What is causing it to be re-done?
In theory the code is the same, with the only differences being in the start position, end position, and increments
Actually it is not the same.
You play with the visibility of the panel and the logic is different depending on which button you click. I'm guessing the setVisible(true) statement is invoking the layout manager which is resetting the location of the component.
There is no need to change the visibility of the panel. Get rid of both setVisible(...) statements.
Also, you might want to keep the buttons enabled you can test sliding in/out repeatedly without restarting the program.
Edit:
if that was the case, why does getX() gives -99
Because the layout hasn't been done when that statement is executed.
Code does not always execute sequentially. Sometimes Swing methods will use SwingUtiltites.invokeLater() to add code the end of the Event Dispatch Thread (EDT).
This is easy enough to verify. Just change your code as follows to see when the layout is invoked.
JPanel panelContainer = new JPanel()
{
#Override
public void doLayout()
{
System.out.println("layout");
super.doLayout();
}
};

Java Timers and TextFields

I have a panel where I have an uneditable Textfield. I want to be able to add a textField.setText(timer); sort of thing in the panel. I basically just want the JTextArea to display it like this: 0:0:0.
I've tried making Timers, TimerTasks, ActionListeners and the sort. I can't get the hang of this. Maybe it's because where I'm adding the timer? At the moment I tried adding it in a public void guiComponents() throws Exception{...}. This method holds all the properties for the panel, the frame it's in and other components.
Maybe I'm not understating the whole concept of timers. Origanlly I tried using a double-nested for loop to achieve this task, but because this has to go on while the rest of the program is running, I couldn't do that.
Don't use a JTextField for this. Use a JLabel to display text. Something like:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class TimerTime extends JFrame implements ActionListener
{
JLabel timeLabel;
public TimerTime()
{
timeLabel = new JLabel( new Date().toString() );
getContentPane().add(timeLabel, BorderLayout.NORTH);
}
public void actionPerformed(ActionEvent e)
{
timeLabel.setText( new Date().toString() );
}
public static void main(String[] args)
{
TimerTime frame = new TimerTime();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setVisible(true);
int time = 1000;
javax.swing.Timer timer = new javax.swing.Timer(time, frame);
timer.setInitialDelay(1);
timer.start();
}
}

How does Thread.sleep really work?

I've made a program that sets a button's setEnable from time to time. The Thread.sleep() is in another class. Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Try extends JFrame implements ActionListener{
JButton n1 = new JButton("1");
JButton n2 = new JButton("2");
JButton n3 = new JButton("3");
JButton show = new JButton("Show");
{
show.addActionListener(this);
n1.setEnabled(false);
n2.setEnabled(false);
n3.setEnabled(false);
}
public Try(){
super("Try");
setVisible(true);
setSize(500, 200);
setLayout(new GridLayout(1, 4));
add(n1);
add(n2);
add(n3);
add(show);
}
public void actionPerformed(ActionEvent a) {
Object clicked = a.getSource();
if(show == clicked){
new EasyLevel1().start();
}
}
class EasyLevel1 extends Thread {
public void run() {
try {
n1.setEnabled(true);
Thread.sleep(1000);
n1.setEnabled(false);
n2.setEnabled(true);
Thread.sleep(1000);
n2.setEnabled(false);
n3.setEnabled(true);
Thread.sleep(1000);
n3.setEnabled(false);
} catch (InterruptedException e){
}
}
}
public static void main(String[] args){
Try frame = new Try();
frame.setVisible(true);
}
}
However, when I put it on my actionListener within the class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Try extends JFrame implements ActionListener{
JButton n1 = new JButton("1");
JButton n2 = new JButton("2");
JButton n3 = new JButton("3");
JButton show = new JButton("Show");
{
show.addActionListener(this);
n1.setEnabled(false);
n2.setEnabled(false);
n3.setEnabled(false);
}
public Try(){
super("Try");
setVisible(true);
setSize(500, 200);
setLayout(new GridLayout(1, 4));
add(n1);
add(n2);
add(n3);
add(show);
}
public void actionPerformed(ActionEvent a) {
Object clicked = a.getSource();
if(show == clicked){
try {n1.setEnabled(true);
Thread.sleep(1000);
n1.setEnabled(false);
n2.setEnabled(true);
Thread.sleep(1000);
n2.setEnabled(false);
n3.setEnabled(true);
Thread.sleep(1000);
n3.setEnabled(false);
} catch (InterruptedException e){}
}
}
public static void main(String[] args){
Try frame = new Try();
frame.setVisible(true);
}
}
It freezes my whole program, based from that example I've understood that a thread sleep should be ran in another thread to stop the current class from freezing. But I expected the new thread.sleep with still freeze its operations like it will still do the code above but the buttons will be responsive since its in another thread. But surprisingly it did what I wanted it to do, It didn't instantly set everything to disabled like the first program.
Thread.sleep() makes the current thread pause. You are running it in an actionPerformed, that is in a Swing Event. All Swing operations are done in a single thread, the EDT. When you pause it with a Thread.sleep(), Swing can not handle any other event because you haven't returned from the actionPerformed listener. Therefore, the GUI freezes (not the complete application, just the GUI).
In general, it is bad practice to do long-running actions in a Swing event because of this. For what you are trying to do, the good alternative is to use Swing timers.
What is happening is that in the 2nd example Thread.sleep is blocking the EDT so no further UI updates occur. In contrast, in the first example you are calling sleep in a separare Thread so no "freezing" occurs. For tasks like this the use of Swing Timers is preferred.
Thread.sleep will cause the thread that executes the call to sleep for the specified time (or until the thread is interrupted). When you call it in the actionPerformed method, it causes the UI thread to sleep. That's why your program is locking up.
You should start a separate thread that will step through the various calls you want to make while sleeping in between. Alternatively (and much better, in my opinion) you could use Swing timers to do what you want.

How to call a method on a period of time in swing?

I have a frame with a JTextField and a JButton.
When I press I want to call a method that updates the JTextField`s text at every 4/5/8 seconds.
Could anyone help me with the code ?? (thank you)
The code:
import javax.swing.*;
public class Gui{
JFrame frame = new JFrame();
public Gui(){
frame.setLayout(new FlowLayout());
JTextField tf = new JTextField(10);
JButton bu = new JButton("Button");
bu.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
for(int i=0;;i++){
tf.setText("" + i);
}
}
});
}
}
Personally, as #trashgod has pointed out, I'd be using the java.swing.Timer, the main reason is that it supports calling notifications within the EDT, as well as some (generally minor) management methods to help make life easier
You could try to use timers : http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
You might want to start the timer when the actionPerformed method is called.
Though BEST bet with Swing, is the use of javax.swing.Timer, as it allows you to update your GUI on the Event Dispatch Thread.

Progress bar to run simultaneously with a function(in another class)

I have created a form on which two components are present, button and progressbar (Netbeans drag and drop).Form contains the main method from where my application starts.I have created another class as well in which i have written a function.What i want is that when i press a button the application goes into the function and the progressbar runs simultaneously with it and when that function is complete with its functionality the the progress bar shows 100% complete.Now this function can take anytime for its completion so i cannot set the max value for the progressbar.So, what to do in this case?Can anyone please provide me with a good example .
JProgressBar.setIndeterminate(true)
Since what sort of a work you are doing inside that so called "Called Function", so it's tough to say, what you want in the scenario, though you can put your lines like progressBar.setValue(someProgress); at regular intervals with it's Indeterminate State to true, and at the end of the function you can simply say that progressBar.setValue(100); and the Indeterminate State will turn to false here, so that it can show that to the end user.
Have a look at this sample program :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ProgressExample
{
public static JProgressBar progressBar;
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Progress Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
JButton button = new JButton("START");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
progressBar.setIndeterminate(true);
WorkingDialog wd = new WorkingDialog();
wd.createAndDisplayDialog();
}
});
contentPane.add(progressBar, BorderLayout.PAGE_START);
contentPane.add(button, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ProgressExample().createAndDisplayGUI();
}
});
}
}
class WorkingDialog extends JDialog
{
private String message = "HelloWorld";
private int count = 0;
private JTextField tfield;
private Timer timer;
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
if (count == 10)
{
timer.stop();
ProgressExample.progressBar.setIndeterminate(false);
ProgressExample.progressBar.setValue(100);
ProgressExample.progressBar.setStringPainted(true);
dispose();
return;
}
tfield.setText(tfield.getText() + message.charAt(count));
count++;
}
};
public void createAndDisplayDialog()
{
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
JPanel panel = new JPanel();
tfield = new JTextField(10);
panel.add(tfield);
add(panel);
pack();
setVisible(true);
timer = new Timer(1000, timerAction);
timer.start();
}
}
So , it seems like you are write
ProgressExample.progressBar.setIndeterminate(false);
ProgressExample.progressBar.setValue(100);
ProgressExample.progressBar.setStringPainted(true);
after your while loop.
You can take a look at my answer in a previous SO question, which contains a sample using a JProgressBar which gets updates from another Thread by using a SwingWorker. Whether or not to use a SwingWorker depends a bit on your use case. If the function take some time to run you better use the SwingWorker to avoid blocking the UI.

Categories

Resources