I have a JFrame that has a button on it that starts a loop. The loop makes the robot click on my screen etc... On The JFrame, how come when the 'x' button is pressed, the program does not terminate? The button does absulotely nothing. I've removed all of the un-relevant code.
This controls the Robot:
package nova;
public class Run {
public static void main(String[] args) throws Exception {
while (true) {
// move
Thread.sleep(Number.random(350, 650));
// click
Control.getPos();
Thread.sleep(Number.random(120, 340));
// move
// click
Control.getPos();
Thread.sleep(Number.random(800, 1000));
// space bar
Thread.sleep(Number.random(11500, 12900));
// move
// click
Control.getPos();
Thread.sleep(Number.random(120, 340));
// move
// click
Control.getPos();
Thread.sleep(Number.random(800, 1000));
// space bar
Thread.sleep(Number.random(11500, 12900));
}
}
}
And this is the JFrame:
package nova;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class Main extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
public Main() {
/*
* JFrame.
*/
setSize(600, 600);// Size of JFrame
setVisible(true);// Sets if its visible.
/*
* JButton.
*/
JButton startButton = new JButton("Start");// The JButton name.
add(startButton);// Add the button to the JFrame.
startButton.addActionListener(this);// Reads the action.
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
onExit();
}
});
}
private void onExit() {
System.exit(0);
}
/*
* The main method.
*/
public static void main(String[] args) {
new Main();// Reads method main()
}
/*
* What the button does.
*/
public void actionPerformed(ActionEvent e) {
// does this when the button is pressed
try {
Run.main(null);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
I am completely confused on why the program is not terminating and closing. How this be resolved?
A Robot is not part of the GUI. It does not execute on the Event Dispatch Thread, so closing the GUI has no effect on it.
How this be resolved?
Add logic in your windowClosing(...) method to stop the Robot. So you will need to somehow restructure your code to get rid the while (true) loop.
Maybe you can create an ArrayList to keep track of all the events you want to generate. Then you can use a Timer to invoke each event. Then in the windowClosing() code you stop the Timer.
Why not just have:
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
Become:
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Related
public void actionPerformed(ActionEvent event)
{
// TODO Auto-generated method stub
JButton src = (JButton) event.getSource(); //get which button is clicked
if(src.equals(GO)) //if GO button is clicked
{
try {
runHack();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(src.equals(STOP)) //if STOP button is clicked
{
//do nothing
FeedBack.setText(null);
FeedBack.setText("Stopped");
}
}
I have a program where when you click on a button GO, it will execute a method called runHack();
private void runHack() throws AWTException
{
FeedBack.setText(null);
FeedBack.setText("Running(This doesn't print out)");
while(true)//infinite loop
{
FeedBack.setText("This doesn't print out");
}
}
runHack() is method that runs an infinite loop. When I click on the GO button, the program freezes while executing the runHack() method. The String "Running" doesn't displayed on the JLabel FeedBack.
My question is how do you make events still available when the program is in the infinite loop? I want it so that when I press on the STOP button, the program exits out of the infinite loop. Also, I want the JLabel FeedBack to work inside the loop.
you need run this infine toop inside of a new thread .this is how to do using timer .swing timer runs in separate thread.set delay to zero.so it's act as a while(true) loop.
in your code you are blocking EDT because of long lasting task(infinite loop) .the changes you made to textfield not get update because EDT is blocked.
you need to swing timer not java.util.Timer
import import javax.swing.Timer;
declare timer
Timer t;//global declaration;
initialize //
t=new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FeedBack.setText("This doesn't print out");
}
});
when button click//
JButton src = (JButton) event.getSource(); //get which button is clicked
if(src.equals(GO)) //if GO button is clicked
{
try {
t.start();
} catch (AWTException e) {
e.printStackTrace();
}
}
if(src.equals(STOP)) //if STOP button is clicked
{
//do nothing
t.stop();
FeedBack.setText(null);
FeedBack.setText("Stopped");
}
updating...
a complete example
import java.awt.AWTException;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.Timer;
public class example extends JFrame implements ActionListener{
Timer t;
private final JTextField FeedBack;
private JButton go;
private JButton stop;
int i=0;
public example() {
FeedBack=new JTextField("initial text");
go=new JButton("go");
stop=new JButton("stop");
go.addActionListener(this);
stop.addActionListener(this);
this.setLayout(new GridLayout(1, 3));
this.add(go);
this.add(stop);
this.add(FeedBack);
this.setVisible(true);
t = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FeedBack.setText(i+"");
i++;
}
});
}
public void actionPerformed(ActionEvent event) {
JButton src = (JButton) event.getSource();
System.out.println(src);
if (src==go) //if GO button is clicked
{
t.start();
}
if (src==stop) //if STOP button is clicked
{
//stop timer
t.stop();
//FeedBack.setText(null);
FeedBack.setText("Stopped");
}
}
public static void main(String[] args) {
example f = new example();
}
}
output>>
Short answer:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run(){
runHack();
}
}).start();
Just take in account that there are better ways to spawn new Threads like using an Executor. Like someone commented, Threads is a broad topic, you should read the documentation.
[EDIT]
Like #Hovercraft Full Of Eels said is not Thread safe calling in a new Thread modifications of the UI.
I need to run a background thread in my Java GUI that only runs when I click a button and pauses when I click that button again. I am not exactly sure how to set this up, but I have placed a thread in my constructor and the while loop within is set to go through when I set a specific boolean to TRUE. One button switches from setting this boolean TRUE or FALSE.
Everything else I have in this GUI works fine. When I tried debugging the thread, it actually works as I step through the thread but nothing when I try running the GUI completely. The GUI is rather large so I'm gonna put up a portion of the constructor and the action listener of the button. The rest of the code is unnecessary since it works just fine. I need to know what I am doing wrong here:
public BasketballGUI() {
// certain labels and buttons
Thread runningSim = new Thread() {
public void run() {
while(simRun) {
// do stuff here
}
}
};
runningSim.start();
}
// other GUI stuff
// actionListener that should run the thread.
class SimButtonListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
if(!simRun) {
simRun = true;
sim.setText("Pause Simulator");
}
else if(simRun) {
simRun = false;
sim.setText("Run Simulator");
}
// other stuff in this actionListener
}
}
Establish a Swing based Timer with an ActionListener that will be called repeatedly.
In the actionPerformed(ActionEvent) method call repaint().
Start the timer (Timer.start()) when the user clicks Start
Stop the timer (Timer.stop()) when the user clicks Stop
If you cannot get it working from that description, I suggest you post an SSCCE of your best attempt.
I thought I had one 'lying around'.. Try this working SSCCE which uses images created in this SSCCE.
I could see this background thread useful for a Java GUI when handling button events to affect something like a text area or progress bar.
For the sake of argument, I will build you a tiny GUI that affects a Text Area. I hope this helps you.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.*;
public class TestClass extends JPanel {
super("TestClass - Title");
private AtomicBoolean paused;
private JTextArea jta;
private JButton btn;
private Thread thread;
public TestClass() {
paused = new AtomicBoolean(false);
jta = new JTextArea(100, 100);
btn = new JButton();
initialize();
}
public void initialize() {
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
add(new JScrollPane(jta));
btn.setPreferredSize(new Dimension(100, 100));
btn.setText("Pause");
btn.addActionListener(new ButtonListener());
add(btn);
Runnable runnable = new Runnable() {
#Override
public void run() {
while(true) {
for(int i = 0; i < Integer.MAX_VALUE; i++) {
if(paused.get()) {
synchronized(thread) {
try {
thread.wait();
} catch(InterruptedException e) {
}
}
}
}
jta.append(Integer.toString(i) + ", ");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
};
thread = new Thread(runnable);
thread.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 30);
}
class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
if(!paused.get()) {
btn.setText("Start");
paused.set(true);
} else {
btn.setText("Pause");
paused.set(false);
synchronized(thread) {
thread.notify();
}
}
}
}
}
Main class to call everything.
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MainClass {
public static void main(final String[] arg) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestClass());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
}
I did not test this code to see if it works exactly, Its main goal is to break you through your coders block and use my components to fix your issue. Hope this helped. Need anything else Email me at DesignatedSoftware#gmail.com
I have a simple code here which adds a label after being clicked. it works fine, but in order to the label to be added i have to drag or reize the window after clicking the button.
Here is my code:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class server01 extends Applet implements ActionListener {
Label helloLabel = new Label("applet v 0.0.1 | created for testing purpose");
Label hello2Label = new Label("this applet will be up-to-date.");
Button buttonButton = new Button("START" + " Button");
Label buttonLabel = new Label("Starting server...");
private static final long serialVersionUID = 1L;
public void init() {
setBackground(Color.black);
setForeground(Color.white);
buttonButton.setForeground(Color.black);
add(helloLabel);
add(hello2Label);
add(buttonButton);
buttonButton.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == buttonButton) {
add(buttonLabel);
}
}
}
use repaint() method in actionPerformed() - (At the method ending) method.
It will repaint the applet window and will run again adding your label.
public void actionPerformed(ActionEvent ae)
{
/*
your code here..
*/
repaint();
}
You need to call the validate method after making gui changes so that the applet can check if it is still rendered correctly.
Doing a resize will basically do the same thing.
public void actionPerformed(ActionEvent e) {
if (e.getSource() == buttonButton) {
add(buttonLabel);
validate();
}
}
I have a public class AppHelper for displaying some help content using a jframe. There is an exit button on the same JFrame which on click disposes the jframe.
The ActionListener is implemented as a static nested class of the class mentioned above.
Also all the components of the help window are defined in the outer class and all of them are private and static. Also the method that shows the help window is static.
Here is some code that I have implemented:
public class AppHelper {
// helper frame
private static JFrame appHelperFrame;
// helper panel
private static JPanel appHelperPanel;
// helper pane
private static JEditorPane appHelperPane;
// exit helper button
private static JButton exitAppHelperButton;
// constraints
private static GridBagConstraints appHelperPaneCons, exitAppHelperButtonCons;
/**
set layout
*/
private static void setLayoutConstraints () {
// defines layout
}
/**
* initialize the helper elements
* #param void
* #return void
*/
public static void initializeElements () {
// initialize constraints
setLayoutConstraints();
// handler
AppHelper.AppHelperHandler appHelpHandler = new AppHelper.AppHelperHandler();
appHelperFrame = new JFrame("App Help");
appHelperPanel = new JPanel();
appHelperPanel.setLayout(new GridBagLayout());
appHelperPane = new JEditorPane();
exitAppHelperButton = new JButton("Exit");
exitAppHelperButton.addActionListener(appHelpHandler);
java.net.URL helpURL = null;
try {
helpURL = new File("AppHelp.html").toURI().toURL();
} catch (MalformedURLException ex) {
Logger.getLogger(AppHelper.class.getName()).log(Level.SEVERE, null, ex);
}
try {
appHelperPane.setPage(helpURL);
} catch (IOException ex) {
Logger.getLogger(AppHelper.class.getName()).log(Level.SEVERE, null, ex);
}
appHelperPane.setEditable(false);
appHelperFrame.add(appHelperPanel);
appHelperPanel.add(appHelperPane, appHelperPaneCons);
appHelperPanel.add(exitAppHelperButton, exitAppHelperButtonCons);
appHelperFrame.setSize(350, 400);
appHelperFrame.setResizable(false);
appHelperFrame.setVisible(true);
}
/**
* TODO
*/
public static void showAboutApp() {
//throw new UnsupportedOperationException("Not yet implemented");
}
/**
*
* Acts as the handler for the help window components
* Implement actionListener interface.
*/
private static class AppHelperHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if(source == exitAppHelperButton) {
appHelperFrame.dispose();
}
}
}
}
The reason of disposing the JFrame instead of setting it invisible is that I dont want this JFrame to consume memory when this JFrame is not in use.
Now the problem is first time I click on the help button (on some other window) the JFrame is shown. Now when I click the exit button on this help window the JFrame is disposed by the handler. Next time I again click on the help button, the help window is not shown. I wanted to know if there is any error in my code or I need to do some thing else.
The javadoc of Window.dispose() states that
The Window and its subcomponents can be made displayable again by rebuilding the native resources with a subsequent call to pack or show.
And that works too, I've tried it. Just call appHelperFrame.setVisible(true) and that's all. If the window is not activated, try calling appHelperFrame.setState(Frame.NORMAL) which will acitvate it.
You only have to call your initializeElements method once though. Your showAboutApp() method should look something like this:
public static void showAboutApp() {
if (appHelperFrame == null)
initializeElements(); // This also makes the frame visible
else {
appHelperFrame.setVisible(true);
appHelperFrame.setState(Frame.NORMAL);
}
}
Final note:
If you always call this showAboutApp() from the EDT (Event Dispatching Thread) then you're good. If you call this from multiple threads, you might want to execute it in the EDT with like SwingUtilities.invokeAndwait() or SwingUtilities.invokeLater() which also ensures synchronization between multiple threads.
I'm making an App. in java , in which there is a Button to which I have added an actionlistener. The ActionEvent it(the button) generates executes some code. Now I want this piece of code to run whenever the app. starts and without pressing the button. I mean, I want to generate the Actionevent (without pressing the button) so that the piece of code the ActionPerformed contains gets executed as the app. start. After that, it may run whenever I press the button.
You can create ActionEvents like any other Java Object by just using the constructor. And then you can send them directly to the component with Component.processEvent(..)
However, in this case I think you are better making your code into a separate function which is called both:
By the ActionListener when the button is pressed
Directly by your application startup code (possibility using SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() if you need it to happen on the event-handling thread)
This way you don't mix up presentation logic with the business logic of whatever the code does....
Yes it can be done, but it doesn't really make sense, since your goal isn't to press a button or to call an ActionListener's code, but rather to have a common behavior on button press and on program start up. To me the best way to achieve this is to have a method that is called by both the actionPerformed method of the ActionListener and by the class at start up.
Here's a simple example. In the code below, a method disables a button, turns the JPanel green, and starts a Timer that in 2 seconds enables the button and resets the JPanel's background color to its default. The method that causes this behavior is called both in the main class's constructor and in the JButton's ActionListener's actionPerformed method:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionOnStartUp extends JPanel {
private static final int PANEL_W = 400;
private static final int PANEL_H = 300;
private static final int TIMER_DELAY = 2000;
private JButton turnGreenBtn = new JButton("Turn Panel Green for 2 seconds");;
public ActionOnStartUp() {
turnPanelGreen();
turnGreenBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
turnPanelGreen();
}
});
add(turnGreenBtn);
}
public void turnPanelGreen() {
setBackground(Color.green);
turnGreenBtn.setEnabled(false);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
setBackground(null);
turnGreenBtn.setEnabled(true);
((Timer) ae.getSource()).stop(); // stop the Timer
}
}).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_W, PANEL_H);
}
public static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ActionOnStartUp());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Usually, the button action event responds to an external event, to notify the application that the user (or rather something or someone) interacted with the application. If your button executes some code that you want to also execute at application start, why not just place everything at it's proper place?
Example:
public class SomeSharedObject {
public void executeSomeCode() { /*....*/ }
}
Set the button with something like
public void setButtonAction(final SOmeSharedObject obj) {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
obj.executeSomeCode();
}
});
}
And run at application start with something like
public void initApplication(SomeSharedObject obj) {
obj.executeSomeCode();
}
And, if the code you need to execute takes a while to complete, you might want to use a separate thread inside your actionPerformed button event so your application UI does not freeze up.
Just Call JButton.doClick() it should fire the ActionEvent associated with the JButton.