How do I break a while loop if I click on my jframe shutdown? I 'm making a clicker that needs to be stopped at some point, but it'll just continue clicking even tho the exit has been pressed.
public class ClickWindow {
private JFrame frame;
private static Clicker click;
private static long currTime;
private static long totalTime;
private JTextField textField;
private static int textFieldValue = 0;
private static Boolean Bool = true;
/**
* Launch the application.
*/
public static void main(String[] args) throws InterruptedException {
click = new Clicker();
ClickWindow window = new ClickWindow();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClickWindow() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setBounds(100, 100, 289, 90);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton btnNewButton_1 = new JButton("Press Space");
btnNewButton_1.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
Bool = false;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
if(textFieldValue == 0){
textFieldValue = 250;
}
try {
while (Bool) {
click.click();
textFieldValue = Integer.parseInt(textField.getText());
Thread.sleep(textFieldValue);
}
} catch (AWTException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
});
btnNewButton_1.setBounds(10, 25, 110, 23);
frame.getContentPane().add(btnNewButton_1);
textField = new JTextField();
textField.setBounds(127, 25, 141, 23);
frame.getContentPane().add(textField);
textField.setColumns(10);
}
public void windowClosing(WindowEvent event) {
Bool = false;
}
}
Clicker class
public class Clicker{
public static void click() throws AWTException{
Robot bot = new Robot();
bot.mousePress(InputEvent.BUTTON1_MASK);
bot.mouseRelease(InputEvent.BUTTON1_MASK);
}
}
Edited with the full code.
You should define the defaultCloseOperation for your JFrame:
JFrame myFrame = new JFrame("MyFrame");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
If you set the defaultCloseOperation, hitting the close button will trigger a call to System exit:
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
JFrame myFrame = new JFrame("MyFrame");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//...add components here
myFrame.pack();
myFrame.setVisible(true);
}
catch (Exception e)
{
System.exit(-1);
}
}
});
}
If you want to shutdown the entire application you can just do this:
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
This will shutdown your application after the Jframe was closed.
You can also call System.exit(0) in your windowClosing method or whenever you want to shutdown your application
instead of adding the keyListener to your JButton try having your JFrame, i.e. ClickWindow implement it. I think this would work.
Related
The game I am building involves switching panels after the start button is clicked when startGame() is called. The program freezes once the button is clicked and does nothing.
Here is code snippet:
public class ArtilleryGame extends JFrame {
private static final long serialVersionUID = 1L;
//TODO: fix clouds from updating with background
static StartPanel startPanel = new StartPanel();
public ArtilleryGame() throws InterruptedException
{
setSize(898,685);
setLocationRelativeTo(null);
setTitle("Tank Game");
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
URL sound = this.getClass().getResource("Sounds/Intro_Screen.wav");
AudioClip drop = Applet.newAudioClip(sound);
drop.loop();
drop.play();
add(startPanel);
//add(new GamePanel());
buttons();
setVisible(true);
}
private void buttons()
{
URL startURL = this.getClass().getResource("imgg/StartBtn.png");
BufferedImage startI = new BufferedImage(170, 62, BufferedImage.TYPE_INT_RGB);
try
{
startI = ImageIO.read(startURL);
} catch (IOException e)
{
e.printStackTrace();
}
ImageIcon startImg = new ImageIcon(startI);
JButton startBtn = new JButton(startImg);
startBtn.setSize(170, 62);
startBtn.setBorder(BorderFactory.createEmptyBorder());
startBtn.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
startGame();
}
});
startBtn.setLocation(365, 310);
StartPanel.background.add(startBtn);
}
public void startGame()
{
remove(startPanel);
add(new GamePanel());
}
public static void displayCredits()
{
JOptionPane.showMessageDialog(null, new CreditsPanel(), "Tank Game", JOptionPane.PLAIN_MESSAGE);
}
public static void main(String[] args) throws InterruptedException
{
new ArtilleryGame();
//displayCredits();
}
}
Use a CardLayout. The CardLayout allows you to easily swap panels.
Read the section from the Swing tutorial on How to Use CardLayout for more information and working examples.
I have two Java(.java) files. One has a JButton and JTextField and the other has a Thread. In first Java file, I have added an ActionListener to the JButton so that, when the button is pressed, a thread (object for 2nd .java file in created and thread is initiated) runs which modifies an integer variable continuously. How to display the value of that integer variable (of 2nd .java file) in the JTextField (of 1st .java file) ?
Detection.java
package sample;
public class Detection implements Runnable
{
public String viewers;
public int count;
public void run()
{
try
{
while (true)
{
// i have written code for displaying video.
// and it say how many no. of people in the video
// the no of people is stored in a variable "count"
viewers=""+count; //storing count as string so as to display in the JTextField
}
}
catch (Exception e)
{
System.out.println("Exception: "+e);
}
}
}
UsrInterfac.java
//build using WindowBuilder eclipse juno
package sample;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class UsrInterfac
{
private JFrame frame;
private JTextField textField;
Detection dd = new Detection();
Thread th = new Thread(dd);
/**
* Launch the application.
*/
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
UsrInterfac window = new UsrInterfac();
window.frame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public UsrInterfac()
{
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize()
{
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton btnStartThread = new JButton("Start Thread");
btnStartThread.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
th.start();
}
});
btnStartThread.setBounds(59, 133, 117, 23);
frame.getContentPane().add(btnStartThread);
textField = new JTextField();
textField.setBounds(270, 134, 104, 20);
frame.getContentPane().add(textField);
textField.setColumns(10);
}
}
Starting from the basics, while using Swing, it is always best to use LayoutManagers, which can make your work much more easier, in comparison to using Absolute Positioning.
Whenever one needs to change something in the View from some another thread, it is always advisable to do that using EventQueue.invokeLater(...)/EventQueue.invokeAndWait(...).
This small sample program, might be able to help you get an idea, how to accomplish what you so desire :-)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ThreadCounter
{
private CustomThread cThread;
private JTextField tField;
private JButton button;
private int counter;
public ThreadCounter()
{
counter = 0;
}
private void displayGUI()
{
JFrame frame = new JFrame("Thread Counter Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
tField = new JTextField(10);
tField.setText("0");
button = new JButton("Start");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
if (counter == 0)
{
cThread = new CustomThread(tField);
cThread.setFlagValue(true);
cThread.start();
counter = 1;
button.setText("Stop");
}
else
{
try
{
cThread.setFlagValue(false);
cThread.join();
}
catch(InterruptedException ie)
{
ie.printStackTrace();
}
counter = 0;
button.setText("Start");
}
}
});
contentPane.add(tField);
contentPane.add(button);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
new ThreadCounter().displayGUI();
}
});
}
}
class CustomThread extends Thread
{
private int changingVariable;
private JTextField tField;
private boolean flag = true;
public CustomThread(JTextField tf)
{
changingVariable = 0;
tField = tf;
}
public void setFlagValue(boolean flag)
{
this.flag = flag;
}
#Override
public void run()
{
while (flag)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
tField.setText(
Integer.toString(
++changingVariable));
}
});
try
{
Thread.sleep(1000);
}
catch(InterruptedException ie)
{
ie.printStackTrace();
}
}
System.out.println("I am OUT of WHILE");
}
}
Ideally you should post your code. Anyway, when you are calling the thread code, either pass the instance of the first class (object) or an instance of JTextField, so that the thread can set the new value in the text field.
In my main Swing frame I have this method:
public void receiveCommand(String command) {
if (command.equals("enable")) {
Runnable enable = new Runnable() {
public void run() {
button1.setEnabled(true);
button1.revalidate();
button1.repaint();
}
};
SwingUtilities.invokeLater(enable);
}
basically, I'm trying to update the GUI (enable the button button1) from outside by calling the receiveCommand() method.
However this doesn't work, i.e button1 is still disabled. What did I do wrong here?
EDIT:
Here is the declaration of button1:
private javax.swing.JButton button1;
button1.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
button1.setEnabled(false);
button1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
button1ActionPerformed(evt);
}
});
Both button1 and the receiveCommand method are in this Game class:
public class Game extends javax.swing.JFrame
The method is called from another class:
gameUI.receiveCommand("enable"); //gameUI is a Game object
EDIT 2: Thank you for all your help! It turns out to be a wrong reference after all, so all I did was trying to update the GUI of a wrong frame that hadn't been set visible yet. Silly me
So anyway, this works.
public class TestInvokeLater {
public static void main(String[] args) {
new TestInvokeLater();
}
public TestInvokeLater() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBorder(new EmptyBorder(12, 12, 12, 12));
final JButton runMe = new JButton("Run me");
runMe.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
runMe.setEnabled(false);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
runMe.setEnabled(true);
}
});
}
}).start();
}
});
setLayout(new GridBagLayout());
add(runMe);
}
}
}
I want the window to close when I press on Cancel button, but it's not working.
Code:
public class FirstClass{
private JFrame frame;
private JButton btnCancel;
public FirstClass() {
frame = new JFrame("GRIIS Data Transfer [Mobile to PC]");
frame.setBounds(200,200,900,450);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
btnCancel = new JButton("Cancel");
btnCancel.setBounds(800, 5, 85, 25);
frame.add(btnCancel);
btnCancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
System.exit(0);
}
});
}
});
}//end of constructor
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
FirstClass window = new FirstClass();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Please let me know in case of changes needed in the code.
btnCancel.addActionListener()
so my code will work and close the application when I press on Cancel button.
Dont use window listner it gives event at time of closing, try
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
No need to override WindowListener method,
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
I'm trying to capture the screen without including my application's window. To do this I first call setVisible(false), then I call the createScreenCapture method, and finally I call setVisible(true). This isn't working however and I'm still getting my applications window in the screen capture. If I add a call to sleep this seems to resolve the issue, but I know this is bad practice. What is the right way to do this?
Code:
setVisible(false);
BufferedImage screen = robot.createScreenCapture(rectScreenSize);
setVisible(true);
Have you tried to use SwingUtilities.invokeLater() and run the capture inside of the runnable passed as an argument? My guess is that the repaint performed to remove your application is performed right after the end of the current event in the AWT-EventQueue and thus invoking the call immediately still captures your window. Invoking the createCapture in a delayed event through invokeLater should fix this.
you have to delay this action by implements Swing Timer, for example
import javax.imageio.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
public class CaptureScreen implements ActionListener {
private JFrame f = new JFrame("Screen Capture");
private JPanel pane = new JPanel();
private JButton capture = new JButton("Capture");
private JDialog d = new JDialog();
private JScrollPane scrollPane = new JScrollPane();
private JLabel l = new JLabel();
private Point location;
private Timer timer1;
public CaptureScreen() {
capture.setActionCommand("CaptureScreen");
capture.setFocusPainted(false);
capture.addActionListener(this);
capture.setPreferredSize(new Dimension(300, 50));
pane.add(capture);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(pane);
f.setLocation(100, 100);
f.pack();
f.setVisible(true);
createPicContainer();
startTimer();
}
private void createPicContainer() {
l.setPreferredSize(new Dimension(700, 500));
scrollPane = new JScrollPane(l,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBackground(Color.white);
scrollPane.getViewport().setBackground(Color.white);
d.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
d.add(scrollPane);
d.pack();
d.setVisible(false);
d.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
f.setVisible(true);
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
});
}
private void startTimer() {
timer1 = new Timer(1000, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
capture.doClick();
f.setVisible(false);
}
});
}
});
timer1.setDelay(500);
timer1.setRepeats(false);
timer1.start();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("CaptureScreen")) {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // gets the screen size
Robot r;
BufferedImage bI;
try {
r = new Robot(); // creates robot not sure exactly how it works
Thread.sleep(1000); // waits 1 second before capture
bI = r.createScreenCapture(new Rectangle(dim)); // tells robot to capture the screen
showPic(bI);
saveImage(bI);
} catch (AWTException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
e2.printStackTrace();
}
}
}
private void saveImage(BufferedImage bI) {
try {
ImageIO.write(bI, "JPG", new File("screenShot.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
private void showPic(BufferedImage bI) {
ImageIcon pic = new ImageIcon(bI);
l.setIcon(pic);
l.revalidate();
l.repaint();
d.setVisible(false);
//location = f.getLocationOnScreen();
//int x = location.x;
//int y = location.y;
//d.setLocation(x, y + f.getHeight());
d.setLocation(150, 150);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
d.setVisible(true);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CaptureScreen cs = new CaptureScreen();
}
});
}
}