I have test method, which start GUI window and next start a endless loop. I want to finish test method when GUI is closing. Any ideas how can I reach it? I try to set a boolean variable and when quit button is pressed I change it to false so loop should be finish but when I look into logs test status is started.
boolean testRunning = true;
JButton buttonQuit;
#Test
public void start() {
MainFrame.getInstance().setVisible(true);
if (showHelpDialog) {
HelpDialog.getInstance().setVisible(true);
}
while(testRunning) {
}
}
And when I pressed quit button testRunning variable is set to false.
I think your problem is, that your blocking the Thread with your UI by executing your loop.
I made an little example with an JFrame. This frame has a JButton as big as the frame. In an Thread is and Loop working until the Button is pressed:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Test {
//to setThe state of the loop
public static boolean continueLoop = true;
public static void main(String[] args) {
//Create a Frame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
Dimension d = new Dimension(400, 400);
frame.setSize(d);
//Add a button to close the programm or end the loop
JButton b = new JButton("Close");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
continueLoop = false;
//Enable this if you want to close the programm
//System.exit(0);
}
});
// Start a Thread with your endless loop in it
Thread t = new Thread(new Runnable() {
#Override
public void run() {
int i = 1;
while(continueLoop)
{
try {
Thread.sleep(500);
System.out.println("Try: " + i);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
// Add a button and set de Frame visible
frame.add(b);
frame.setVisible(true);
}
}
Hope that helps!
PS: this is the fastest example i could think of. Note that there are better ways to add a state-controled loop to your UI. For example I used static variables for my example - you should not do that in your application - except it really necessary.
Related
I am slightly confused, I have a jFrame of which I have made in Netbeans. This jFrame has a jLabel, of which is set to setVisible(false); from the beginning. Whenever a specific method is called, I then set the jLabel to setVisible(true); and then use a timer to set it to false again after 2 seconds. Apparently it won't work and I am unable to figure out why. I am aware of the repaint(); method, but can figure out how to make that work either.
I know the actual method for setting the visibility is called, as I have set it to print a line with the current state, which it does.
My actual code is the one below.
public JFram() {
initComponents();
setResizable(false);
jLabel2.setVisible(false);
}
static void tesMethod() {
try {
//function that does something
} finally {
new JFram().showHide(); //call function which is supposed to change the vissibility of jLabel
}
}
void showHide() {
jLabel2.setVisible(true);
System.out.println("reached show");
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
jLabel2.setVisible(false);
System.out.println("reached timer");
}
},
2000
);
}
The code below here is how I tried to use the repaint(); method.
void showHide() {
jLabel2.setVisible(true);
jLabel2.repaint();
System.out.println("reached show");
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
jLabel2.setVisible(false);
jLabel2.repaint();
System.out.println("reached timer");
}
},
2000
);
}
I think your problem lies mainly in you using a java.util.Timer instead of a javax.swing.Timer and probably you're blocking the Event Dispatch Thread (EDT).
You could try this code and compare it with yours, I also don't see where you're adding your JLabel to your frame.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ShyLabel {
private JFrame frame;
private JLabel label;
private Timer timer;
private boolean isVisible;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShyLabel().createAndShowGui();
}
});
}
public void createAndShowGui() {
String labelText = "I'm a shy label that hides every 2 seconds";
isVisible = true;
frame = new JFrame(getClass().getSimpleName());
label = new JLabel(labelText);
timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(isVisible ? "" : labelText);
isVisible = !isVisible;
}
});
timer.setInitialDelay(2000);
timer.start();
frame.add(label);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
The below image is produced by the above code, however because of the time I recorded the GIF it looks really fast instead of taking 2 seconds as it should be...
May be it is a problem of layout.
As you set resizable to false before any layout calculation occurred, the label was ignored (as invisible) by the time of the first layout.
You could try revalidate().
I want to move a button towards another button automatically. please help me out to solve this I just learned sleep method . may some problems their applying
import javax.swing.*;
import java.awt.*;
public class tr extends JFrame
{
public static void main(String []args)
{
JFrame f1=new JFrame("Hit & Run");
JPanel p1=new JPanel();
JButton mv = new JButton();
JButton hit=new JButton("Hit It");
f1.getContentPane().add(p1);
int x;
for(x=0;x<=600;x++)
{ try{
Thread.sleep(50);
}
catch(InterruptedException e)
{
System.err.println("sleep exception");
}
mv.setBounds(x,220,53,35);
}
hit.setBounds(680,30,90,500);
p1.setBackground(Color.black);
hit.setBackground(Color.green);
mv.setBackground(new Color(255,204,0));
p1.setBackground(Color.black);
p1.setLayout(null);
p1.add(mv);
p1.add(hit);
f1.setVisible(true);
f1.setSize(800,600);
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
With your current code your programm sleeps alot while is not even finish with creating your window. And first of all never send your GUI Thread to sleep or your Window will sleep while it should be awake and interact with the user.
To do what you want you need to start another Thread that will perform the movement of your button.
So take your for loop out of the initialization code and add the following under your last line.
new Thread(new Runnable(){
#Override
public void run() {
int x;
for(x=0;x<=600;x++)
{
try{
Thread.sleep(50);
}
catch(InterruptedException e)
{
System.err.println("sleep exception");
}
mv.setBounds(x,220,53,35);
}
}
}).start();
I'm attempting to make a program in java that uses a robot to press a specific key every few seconds. It has a GUI with a start and stop button and a label which tells which state its in. I've got everything working so far except that when I click "start" it runs the loop for my robot function (which is infinite) it doesn't enable the stop button like I thought it would. I know its something stupid with where the infinite loop is placed but I'm not sure how to make it work correctly.
I don't do a lot of java work, this was just a fun thing I thought to try but got stuck part way through. Any help is appreciated.
import java.awt.AWTException;
import java.awt.FlowLayout;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private static boolean running = false;;
private JButton start_button;
private JButton stop_button;
private JLabel tl;
private static int i = 0;
Robot robot;
void start() {
JFrame frame = new JFrame("Helper");
tl = new JLabel("Running: " + running);
start_button = new JButton("Start");
stop_button = new JButton("Stop");
stop_button.setEnabled(false);
frame.add(tl);
frame.add(start_button);
frame.add(stop_button);
frame.setSize(300, 100);
frame.setVisible(true);
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocation(400, 400);
try {
robot = new Robot();
} catch (AWTException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
robot.setAutoDelay(200);
start_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(false);
stop_button.setEnabled(true);
running = true;
tl.setText("Running: " + running);
while (running) {
robot_loop(robot);
}
}
});
stop_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(true);
stop_button.setEnabled(false);
running = false;
tl.setText("Running: " + running);
}
});
}
public static void main(String[] args) {
new Main().start();
}
private static void robot_loop(Robot robot) {
robot.keyPress(KeyEvent.VK_NUMPAD0);
robot.keyRelease(KeyEvent.VK_NUMPAD0);
System.out.println("numpad 0 pressed! - " + i);
i++;
}
}
I've adapted my comment into an answer.
The actionPerformed method of those event listeners are invoked on Swing's event dispatch thread, and since you're entering into an infinite loop, it'll cause the GUI to freeze. You could create a thread inside of your actionPerformed method and do your work inside of the new thread. Though the next issue you'd run into is finding a nice way to stop the thread whenever the user presses the stop button.
What's cool is that you've already got all the logic to do this in your code. So getting it to work is as simple as changing:
start_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(false);
stop_button.setEnabled(true);
running = true;
tl.setText("Running: " + running);
while (running) {
robot_loop(robot);
}
}
});
To do your work on its own thread:
start_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(false);
stop_button.setEnabled(true);
running = true;
tl.setText("Running: " + running);
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override public void run() {
while (running) {
robot_loop(robot);
}
}
});
}
});
The code above makes use of the executors framework (java.util.concurrent.*) rather than directly creating a thread. Another alternative as nachokk suggested would be to use a timer java.util.Timer or javax.swing.Timer (either should be fine in this case).
You can do something like this using SwingTimer
int delay = 400*1000;// you can inject this property
ActionListener taskPerformer = new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt2) {
robot_loop(robot);
}
};
Timer timer = new Timer(delay, taskPerformer);
timer.start();
I'm trying to:
display a text in a jLabel,
wait for two seconds,
then write a new text in the jLabel
this should be simple, but I get a strange bug:
the first text is never written, the application just waits for 2 seconds and then displays the final text. here is the example code:
private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {
displayLabel.setText("Clicked!");
// first method with System timer
/*
long t0= System.currentTimeMillis();
long t1= System.currentTimeMillis();
do{
t1 = System.currentTimeMillis();
}
while ((t1 - t0) < (2000));
*/
// second method with thread.sleep()
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {}
displayLabel.setText("STOP");
}
with this code, the text "Clicked!" is never displayed. I just get a 2 seconds - pause and then the "STOP" text.
I tried to use System timer with a loop, or Thread.sleep(), but both methods give the same result.
Just to provide more background on Andrew Thompson's comment: the EDT is responsible for handling gui updates. If you block it using Thread.sleep(...) those updates are blocked as well. That's why you don't see the first text - the EDT just can't do the update on the label.
Here's a runnable example which does what you're after. As Andrew Thompson's comment stated, a SwingWorker is a good way to approach this problem.
The basic principal is to never block the Event Dispatch Thread. That's the thread responsible for repainting the GUI and responding to user interaction, so if you do something computationally expensive on the EDT, your GUI will stop responding.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
public class ButtonTest {
public static void main(String[] args) {
// create a frame and a button
JFrame frame = new JFrame();
final JButton button = new JButton("Button");
frame.add(button);
// add an action listener to the button
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// change the button text right away
button.setText( "Clicked" );
// create a SwingWorker which simply waits 2000 milliseconds
// simulating a computation being performed
SwingWorker<String, Object> worker = new SwingWorker<String, Object>() {
#Override
public String doInBackground() {
// it's safe to call Thread.sleep( ) here
// doInBackground is executed on a separate worker
// thread
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return "Done";
}
#Override
protected void done() {
// done() is executed back on the Swing thread
// so it's safe to updated the state of the button
try {
button.setText(get());
} catch (Exception e) { }
}
};
// run the worker
worker.execute();
}
});
frame.setSize( 300, 300 );
frame.setVisible( true );
}
}
You are messing with the event dispatcher thread.
That will cause un-expected UI behavior as you are seeing. If you plan to do these type of animations, make sure to read up on what #Andrew Thompson suggested and also, see if you can read this - Filthy rich clients
Better to use a Swing Timer as shown in curde-example below:(yes, it is crude, I did not worry about stopping the timer etc):
public class DelayTest extends JPanel{
JLabel messageLabel = new JLabel();
JButton actionButton = new JButton("Click Me");
String[] messages = {"Clicked", "Stop!"};
int i=0;
public DelayTest(){
super();
add(messageLabel);
add(actionButton);
actionButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if(i<=1)
messageLabel.setText(messages[i++]);
}
});
timer.start();
}
});
}
}
Edit
Why not stop the Timer:
#Override
public void actionPerformed(ActionEvent evt) {
if (i <= 1) {
messageLabel.setText(messages[i++]);
} else {
((Timer)evt.getSource()).stop();
}
}
});
In my java swing application am having a Jframe and Jlabel for displaying current time.
here am using a thread for displaying time in jlablel which is added to the frame.my doubt is that when i dispose the jframe what will happen to the thread whether its running or stopped.
If you have NOT marked your thread as daemon by calling yourThread.setDaemon(true), it will keep running even if main thread in your application has finished. Remember you have to call setDaemon before starting the thread.
Refer my answer to some previous question for details.
The correct way in your case, I believe, would be you maintain a 'stop' flag which is watched by your timer thread. Timer thread should exit on reading this flag as 'false'. You can add a WindowListener to your jframe and on the window closed event set the 'stop' flag to true
Heres example code for what I am suggesting :
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
public class JFrameTest {
public static void main(String[] args) {
final Timer t = new Timer();
t.start();
JFrame jf = new JFrame("GOPI");
jf.setVisible(true);
jf.setSize(100, 100);
jf.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
t.stopTimer();
}
});
System.out.println("JFrameTest.main() DONE");
}
}
class Timer extends Thread {
boolean stop = false;
#Override
public void run() {
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (stop)
break;
System.out.println("Counting :" + i);
}
System.out.println("Timer exit");
}
public void stopTimer() {
stop = true;
}
}
Your thread will keep running.
You need to either do as suggested by Gopi or you could use System.exit(0) in close operation of your JFrame.
NOTE: I am assuming here that Your application needs to end if this Frame is closed.