Null Pointer Exception when program not run through debugger - java

I am developing a game in Java for a school project. When I run my code by typing 'java game' into the command prompt, I get a null pointer exception (at game.play, line 35, "gameScreen.tick();"), however when I add a breakpoint on this line and use a debugger to investigate, the debugger shows the correct object reference and follows the program without any problems. I can't seem to work out what is wrong...
import javax.swing.*;
public class game implements Runnable {
private screen gameScreen;
public static void main(String[] args) {
// put your code here
game thisGame = new game();
SwingUtilities.invokeLater(thisGame);
thisGame.play();
}
public void run() {
JFrame w = new JFrame();
w.setDefaultCloseOperation(w.EXIT_ON_CLOSE);
gameScreen = new screen();
gameScreen = gameScreen.setUp();
w.add(gameScreen);
w.pack();
w.setLocationByPlatform(true);
w.setVisible(true);
}
public void play() {
while(true) {
try { Thread.sleep(10); }
catch (InterruptedException e) { }
}
gameScreen.tick();
}
}
Any help would be appreciated! Thanks.

invokeLater() is an asynchronous call and will be invoked later as the name suggests.
Your next line calls thisGame.play() which in turn calls gameScreen.tick() after 10ms which may be uninitialized at the time.
The reason that the debugger works, is that the wait is probably long enough between method calls to allow gameScreen to be initialized by the run() method

Documentation gives below example for SwingUtilities.invokeLater method.
Runnable doHelloWorld = new Runnable() {
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
}
};
SwingUtilities.invokeLater(doHelloWorld);
System.out.println("This might well be displayed before the other message.");
You can see This might well be displayed before the other message. might print before Hello World on.
So in your case gameScreen = new screen(); might not be executed before gameScreen.tick();, so you are getting NPE.
Solution:
You can initialize gameScreen in the default constructor of game class.

Related

Breaking a Loop With a JButton

I'm creating a program for a game that clicks in random intervals for X seconds with Y time between each click. Here is the code that does this.
try {
Util.autoCode rand = new Util.autoCode();
Robot robot = new Robot();
int NoC;
NoC = Integer.parseInt(this.numberOfClicksTF.getText().trim());
if (NoC == 0) {
while (NoC == 0) {
// robot.mousePress(InputEvent.BUTTON1_MASK);
System.out.println("Infinite Press");
Thread.sleep(rand.clickDelay());
System.out.println("Infinite Release");
// robot.mouseRelease(InputEvent.BUTTON1_MASK);
Thread.sleep(rand.interval());
break;
}
} else {
for (int i = 0; i < NoC; i++) {
//robot.mousePress(InputEvent.BUTTON1_MASK);
System.out.println("Click Press");
Thread.sleep(rand.clickDelay());
System.out.println("Click Release");
// robot.mouseRelease(InputEvent.BUTTON1_MASK);
Thread.sleep(rand.interval());
}
}
} catch (AWTException ex) {
Logger.getLogger(MainFrame.class
.getName()).log(Level.SEVERE, null, ex);
} catch (NumberFormatException ex) {
Logger.getLogger(MainFrame.class
.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
I commented out the mouse press and release just so I could do a check to make sure the timing was right, and that it would perform each click. This code is started by JButton in a JFrame. Whenever I press the start button, it starts the code and nothing but force closing it in Netbeans will stop it. The goal is to have a start button initiate, and a stop button interrupt the code, but not close the JFrame. I have been looking everywhere and haven't been able to find a straight answer.
Any help is welcomed and appreciated!
You need tu use SwingWorker, for example:
in your JFrame you may have a SwingWorker and it "builder" method:
private SwingWorker worker;
private SwingWorker getWorker() {
worker = worker == null ? worker = new SwingWorker() {
#Override
protected Object doInBackground() throws Exception {
while (true) {
System.out.println("doInBackground!");
Thread.sleep(1000);
}
}
} : worker;
return worker;
}
now, in the swing main thread (used for visual components updates) you need to call the SwingWorker with your background task:
private void jButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (getWorker().getState().equals(SwingWorker.StateValue.STARTED)) {
worker.cancel(true);
worker = null;
} else {
getWorker().execute();
}
}
You can click on the button as many times as you wish, the app will create and run a SwingWorker or kill and set to null the current SwingWorker.
Literally ran into your exact same problem this week trying to make almost the same thing. First, let me suggest reading up on multithreading in Java. It may seem complicated, but trust me it's necessary to understand why your program is not working. (I'll give a run down of what's happening below)
Essentially, your GUI is running on an Event Dispatcher Thread that needs to be separated from your robot. That is because when you call thread.sleep(), you essentially tell the GUI thread to sleep too, resulting in loss of GUI control. Start your robot and GUI in separate threads and have your JButtons invoke methods to get your robot thread to start and stop. For example:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GUI();
}
});
}
To create your GUI(I don't know what your GUI is like, so I just wrote new GUI() to substitute for how you created yours), that way it's in the thread it's supposed to be in. Then in your eventListener, spawn a new thread holding the robot object everytime the start button is pressed:
if(actionEvent.getSource().equals(playButton)) { //listening for the play button
if(robotThread == null) {
autoClicker= new AutoClicker();
Thread = new Thread(autoClicker);
Thread.start();
}
}
And initiate your robot object in the autoClicker() class like you did, and have autoClicker implement runnable.
public class AutoClicker implements Runnable{
private Robot robot;
public void run(){
try {
robot = new Robot();
} catch (AWTException e) {e.printStackTrace();}
//you need to learn about synchronization first
while(true){
synchronized(this){
//do clicks and stuff here
}
}
}
}
This way, your GUI and robots are in separate threads. In order to make JButtons start and stop your robot, you're going to need to learn synchronization to know how to properly multithread.
Another thing is that you should probably use the wait() method instead of sleep(), as sleep() would cause a lot more problems that's too much to go through in a single answer. Again, you need to learn concurrency/synchronization first.
If you want comment below and we can work out a way for me to DM you my code I'm working on right now, which is the exact same thing as you're trying to make. I can explain every part of it to you to help you on your way.

Java - Swing GUI doesn't load

I've been trying to learn java for a few weeks now, and I'm working on a pretty simple autoclicker.
The clicker itself works, but my problem is that my GUI never shows up.
The GUI runs just fine when I run the GUI file itself, but when I'm trying to run it from my main program (different file) it never shows. The clicker works fine all the time though. I'm sure the problem is something really simple that I have simply missed, but this is now my 4th day without any clue on what might be wrong with it, so decided I'd ask here.
Beware - the code is really messy atm, because I've been trying pretty much everything possible to get it working.
This is the code in the main program trying to run the GUI.
package autoclicker;
import java.awt.AWTException;
/**
* The main program for the autoclicker.
*/
public class AutoClicker {
public static void main(String[] args) throws AWTException {
Click click = new Click(true);
click.clicker();
try {
Swingerinos sw = new Swingerinos();
sw.initialize();
}
catch (AWTException e) { e. printStackTrace(); System.exit(-1); }
}
}
And this is the whole GUI file.
package autoclicker;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Swingerinos extends Click implements WindowListener,ActionListener {
private int numClicks = 0;
TextField text;
private JFrame frame;
/**
* #wbp.nonvisual location=181,19
*/
private final JLabel lblAutoclicker = new JLabel("AutoClicker");
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Swingerinos window = new Swingerinos();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Swingerinos() throws AWTException {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 109);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.WEST);
JButton btnNewButton = new JButton("Toggle On / Off");
text = new TextField(20);
text.setLocation(100, 100);
btnNewButton.addActionListener( this);
btnNewButton.setToolTipText("Toggles the autoclicker on / off.");
panel.add(btnNewButton);
panel.add(text);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
toggle();
numClicks++;
text.setText(""+numClicks);
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowOpened(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
}
I know the GUI file is really messy (there's 2x initialize(), one in the main program and one in the GUI file, and lots of other stuff, but I'm just too confused as for what to do now.
EDIT: I added the whole main program code, also this is the code for the autoclicker.
package autoclicker;
import java.awt.*;
import java.awt.event.InputEvent;
public class Click {
private boolean active;
private Robot robot;
public Click(boolean active, Robot robot) {
this.active = active;
this.robot = robot;
}
public Click() throws AWTException {
this(false, new Robot());
}
public Click(boolean active) throws AWTException {
this(active, new Robot());
}
//TODO: add click.toggle() to somewhere and control da clicker
public void toggle() {
active = !active;
}
public void clicker() {
while (active) {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.setAutoDelay(10000);
}
}
}
Expanding JB Nizet's comment(s) into an answer.
The immediate cause:
When the JVM calls your code, it is run on the main thread. It calls main(String[]), as you know. You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]). Let's go through it:
Click click = new Click(true);
click.clicker();
This first of the above two lines obviously calls the constructor of Click, which sets the active variable to true. So far so good. The second line is much more interesting. It calls Click#clicker(). Let's look at that method:
public void clicker() {
while (active) {
// <snip>
}
}
This method is the problem. Since you haven't started any other threads, the main thread is the only one you have at that moment, the only thread on which you can execute code. When this loop is executed it only finishes when the active variable is set to false. As long as it is true, it will keep looping. This means that Click#clicker() only returns if active is set to false. But, you never do that in the loop itself, meaning you need a thread different from the thread executing the loop to change active. So, how many threads do we have? 1, the main thread. See the problem? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker().
Simple solution
You could just set a fixed number of iterations:
public void clicker() {
int i = 0;
while (i < 100) { // iterate 100 times
// <snip>
++i;
}
}
Or using a for-loop (recommended):
public void clicker() {
for (int i = 0; i < 100; ++i) {
// <snip>
}
}
This eliminates the need for the active variable and hence the need for another thread.
A somewhat more complicated solution
If you really want the active variable, you'll need to have multiple threads. This is conveniently known as "multithreading"1, a very complicated topic. Luckily, we only need a bit of it, so it is only a bit complicated.
Don't just call the method Click#clicker() like you would normally. This creates your current problem. You'll need a worker thread, which can call the method. The easiest way to create a new thread is to call the constructor of the class Thread which takes a single argument of type Runnable. Like this:
Thread worker = new Thread(new Runnable() {
public void run() {
click.clicker();
}
});
This returns relatively quickly and leaves the Click#clicker() method running on another thread. Your main thread is now free to execute the other statements and even call click.toggle() after a while.
As JB Nizet pointed out, there are some other problems with your code. For example, Swingerinos shouldn't extend Click, but have an instance variable of type Click (http://en.wikipedia.org/wiki/Composition_over_inheritance) (as JB Nizet pointed out). Also, you shouldn't need to implement WindowListener to just call System.exit() when the window closes if you already call frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. To get all kinds of feedback (not limited to but including this kind of issues, style and design) on working code2 I highly recommend the StackExchange website codereview.stackexchange.com
1: I by no means consider myself even remotely an expert on threading, so I won't go into it. If you want to know more about it, google it - there's lots of texts on multithreading - or ask another question - if you have a specific problem.
2: this is important: broken code is off-topic on Code Review.

UI thread can not start after IDE changed

I changed my IDE from Eclipse to IntelliJ IDEA. The new one started complaining about my code.
public class Controller {
private OknoGlowne frame;
private MenuListener menuListen = new MenuListener(this);
private TabListener tabListener = new TabListener(this);
public OknoGlowne getFrame() {
return frame;
}
public Controller(){
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new OknoGlowne();
frame.setVisible(true); //error
frame.addMenuListener(menuListen);
frame.addTabListener(tabListener);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
So I commented this line. And add new line to constructor of UI frame.
public OknoGlowne() {
jPanel.setVisible(true);
}
App start but UI doesn't show any more. IDEA create frame in different way than Eclispe. I have to switch.
Main
public class Runner {
public static void main(String[] args) {
new Controller();
}
}
This doesn't really have anything to do with your IDEs. I bet if you ran it 100 times in eclipse, or from the command line, you'd get different results depending on how busy your system is.
The reason you aren't seeing the JFrame pop up is because you're using invokeLater() instead of invokeAndWait().
The invokeLater() method immediately returns, at which point you're in a race condition: will the event thread display the EDT first, or will the main thread exit first? If the main thread exits first, then your program will exit before any windows are shown.
To prevent this, you have to use invokeAndWait() instead of invokeLater().

What is the correct way to implement this do while?

I start my GUI like this, which seems correct.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame gui = new JFrame();
gui.setExtendedState(JFrame.MAXIMIZED_BOTH);
gui.setVisible(true);
}
});
At a certain point in the application, the playTurn() method gets fired. The for loops all turns in the list.
for (String turn : controller.getTurns()) {
playTurn(turn);
}
I now load the correct panel with my CardLayout which worked fine. Then I had to write the playTurn() method. So playTurn() gets called. It should do certain things according to some variables. But it should not return until some buttons are disabled. This is what I can't achieve, the program just stops working. I can guess it's in the direction of threads etc.. but can't seem to figure it out. Thanks in advance.
public void playTurn(String turn) {
if (controller.givePlayers().contains(turn)) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
while (!turnFinished) {
if (!button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled()) {
turnFinished = true;
}
}
}
});
} else {
deletePlayer(turn);
}
}
Sorry for bad formatting. Couldn't find where.
EDIT:
The GUI stops being responsive. Can't close program either.
I tried using a SwingWorker for the while which does not block the GUI but still playTurn() returns.
I have even tried creating a new thread where I call the method. The doesn't get blocked anymore but the method still returns.
Thread one = new Thread() {
public void run() {
playTurn(turn);
}
};
FIXED: Placing the runnable up higher in the stack;
Your playTurn method runs the code on the EDT, cause of this line javax.swing.SwingUtilities.invokeLater(new Runnable() {, which makes your application GUI unresponsive as GUI-changing code must generally be run on the EDT. Since your buttons won't change from your GUI, once the loop starts, it might just loop forever.
By running the code in another Thread, you won't freeze your GUI. I'm guessing, since you don't provide much informations on the rest of your code, that you might have to change the way you handle things once your loop is done.
Edit from comments : Since you don't want playTurn to return, don't use a thread within it and make sure playTurn is not running on the EDT. Your playTurn method will return after creating and making a new Thread run the code.
You might want to try dong it like this :
Runnable code = new Runnable() {
#Override
public void run() {
for (String turn : controller.getTurns()) {
playTurn(turn);
}
}
};
if (!SwingUtilities.isEventDispatchThread()) {
code.run();
} else {
new Thread(code).start();
}
To make sure you don't run the code on the EDT. That way, playTurn doesn't return until the loop condition is met, the GUI stays responsive.
public void playTurn(String turn) {
if (controller.givePlayers().contains(turn)) {
while (!turnFinished) {
if (!button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled()) {
turnFinished = true;
}
}
} else {
deletePlayer(turn);
}
}
Doing this might have you change a few things more.
The idea is to make the call to a new Thread where you don't want it/need it to wait for the code being run in a new Thread to end to continue.

Wait for Swing Interface to close before proceeding

I've been searching near and far for a solution to my question but I am having difficulty even defining my search terms.
I have a method that creates a Swing GUI using invokeLater where the user completes some task. Once the task is completed, the window closes and the initial calling thread (e.g. the method) should resume execution. To be more specific, here is a summary of the method:
public class dfTestCase extends JFrame{
public dfTestCase{
... //GUI code here
}
public String run()
{
CountDownLatch c = new CountDownLatch(1);
Runnable r = new Runnable()
{
public void run()
{
setVisible(true); //make GUI visible
}
};
javax.swing.SwingUtilities.invokeLater(r);
//now wait for the GUI to finish
try
{
testFinished.await();
} catch (InterruptedException e)
{
e.printStackTrace();
}
return "method finished";
}
public static void main(String args[]){
dfTestCase test = new dfTestCase();
System.out.println(test.run());
}
}
Within the GUI, I have actionListeners for buttons that will close and countDown the CountDownLatch.
While the CountDownLatch works, it is not suitable for my purposes because I need to run this GUI several times and there is no way to increment the latch. I'm looking for a more elegant solution - it is my best guess that I would need to make use of threads but am unsure how to go about this.
Any help would be much appreciated!
Update
Some clarification: What is happening is that an external class is calling the dfTestCase.run() function and expects a String to be returned. Essentially, the flow is linear with the external class calling dfTestCase.run()-->the GUI being invoked-->the user makes a decision and clicks a button-->control to the initial calling thread is returned and run() is completed.
For now my dirty solution is to just put a while loop with a flag to continuously poll the status of the GUI. I hope someone else can suggest a more elegant solution eventually.
public class dfTestCase extends JFrame{
public dfTestCase{
... //GUI code here
JButton button = new JButton();
button.addActionListener{
public void actionPerformed(ActionEvent e){
flag = true;
}
}
}
public String run()
{
Runnable r = new Runnable()
{
public void run(){
setVisible(true); //make GUI visible
};
javax.swing.SwingUtilities.invokeLater(r);
//now wait for the GUI to finish
while (!flag){
sleep(1000);
}
return "method finished";
}
public static void main(String args[]){
dfTestCase test = new dfTestCase();
System.out.println(test.run());
}
}
Modal dialogs and SwingUtilities#invokeAndWait iso invokeLater should allow you to capture user input and only continue the calling thread when the UI is disposed
For an example of using model dialogs you can check out the ParamDialog class I wrote. In particular, check out ParamDialog.getProperties(Properties);
http://tus.svn.sourceforge.net/viewvc/tus/tjacobs/ui/dialogs/

Categories

Resources