Null Pointer with JButton Array - java

So far I have created a frame at adds my ControlPanel class, the class takes an int, and that int is used to fill an array with JButton objects which are the added to a Panel and displayed.
However I am getting a Null Pointer error when I try to add JButtons to the array. I'm not sure why (since I thought null pointers were from when you try to reference something that isn't in the spot in the array?)
Any help on this would be great appreciated.
Error Message:
Exception in thread "main" java.lang.NullPointerException
at elevator.ControlPanel.<init>(ControlPanel.java:22)
at elevator.Elevator_Simulator.main(Elevator_Simulator.java:27)
Main Class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
public class Elevator_Simulator extends JFrame {
public static void main(String[] args) {
JFrame frame = new JFrame ("Elevator Simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ControlPanel(8));
frame.pack();
frame.setVisible(true);
}
}
Control Panel Class:
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
public class ControlPanel extends JPanel implements ActionListener {
public JButton[] floorButton; // an array of floor buttons.
public int[] floorIn; // state of button. 0 == not click >= 1 means clicked (how many times).
public ControlPanel(int x) {
JPanel floors = new JPanel();
for (int i = 0; i < x; i++) { // interates through user input and creates that many JButtons.
floorButton[i].add(new JButton("F" + Integer.toString(i))); // adds a button to button array. Sets text to F(floorNo).
floors.add(floorButton[i]); // adds buttons to the floor panel.
floorButton[i].addActionListener(this); // adds action listener to the buttons.
}
}
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < floorButton.length; i++) {
if (e.getSource() == floorButton[i]) { // checks which button the event occured on.
floorButton[i].setBackground(Color.red); // sets button background to red.
floorButton[i].setText(floorButton[i].getText() + "(1)"); // marks button as clicked.
}
}
}
}

floorButton is not initalised to anything...
public JButton[] floorButton; // I'm null
public ControlPanel(int x) {
//...
for (int i = 0; i < x; i++) { // in
// Still null
floorButton[i].add(new JButton("F" + Integer.toString(i)));
Initalise the array to reflect what you need, also, don't use floorButton[i].add, you don't want to add the button to (what is currently a null element) button, you want to assign it to the position of the array...
public ControlPanel(int x) {
//...
floorButton = new JButton[x];
for (int i = 0; i < x; i++) { // in
floorButton[i] = new JButton("F" + Integer.toString(i));
I'm guessing you'll want to do the same with floorIn...

You have to initialize your floorButton.
floorButton = new JButton [yourCount];

You created the array of JButton, but you didn't create every element in the array. To do this:
Replace this:
floorButton[i].add(new JButton("F" + Integer.toString(i)));
by this:
floorButton[i] = new JButton("F" + Integer.toString(i));

Related

Can't update JLabel array

I'm writing a thing that has a JLabel array that has something in the first index and then detects right keys that shifts the thing to the right. Basically, [x][][][][][][] starts, then if I press the right key, it shifts to [][x][][][][][]. Currently, I can't get the JLabel to properly update. It shows up correctly at first, but when I hit the right key, the entire thing gets messed up. Ie, it starts like this:
(I have the numbers to gauge the shifting, they'll go away when I figure this problem out)
Which is right, but when I hit the right key, everything disappears (just blank.) However, my test in the console still gives me the correct values though.
The numbers don't even show up :/
Here's the relevant code:
public Template() {
for (int i = 0; i < 7; i++) {
positions[i] = new JLabel();
positions[i].setFont(new Font("Times New Roman", Font.PLAIN, 15));
System.out.println("Yay");
}
// I initialize my JLabel array here instead of below because if I don't do this, there's no change whatsoever if I press the right key. I'm not sure if I did it correctly, though.
initialize(p1, 0);
}
private void initialize(String p, int index) {
frame = new JFrame();
JPanel header = new JPanel();
header.setBackground(Color.WHITE);
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
header.setLayout(gbl);
header.setPreferredSize(new Dimension(400, 50));
c.fill = GridBagConstraints.HORIZONTAL;
for (int i = 0; i < 7; i++) {
if (i == index) {
positions[i].setText(p + "");
System.out.println("indexed set");
} else {
positions[i].setText("" + i);
System.out.println(positions[i].getText());
System.out.println("set");
}
c.gridx = i;
c.gridy = 0;
header.add(positions[i], c);
}
frame.add(header, BorderLayout.NORTH);
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
playMove(p);
}
public void playMove(String p) {
...
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent keyEvent) {
System.out.println("Game.keyPressed -- event: " + keyEvent);
if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right key pressed!");
int index = searchHeader();
System.out.println("index: " + index);
if (index != 6) {
int shift = index + 1;
System.out.println("shift: " + shift);
SwingUtilities.updateComponentTreeUI(frame);
initialize(p, shift, t);
}
}
}
#Override
public void keyReleased(KeyEvent keyEvent) {
System.out.println("Game.keyReleased -- event: " + keyEvent);
}
});
}
public int searchHeader() {
for (int i = 0; i < 7; i++) {
String val = positions[i].getText();
if (val == "x" || val == "o") {
System.out.println("i:" + i);
return i;
}
}
return 0;
}
My System.out.println(); tests all return the correct values (the correct index, shift, and numbers in the array) but I'm not sure why the thing isn't showing up :/
If my code needs clarification or missed something (I did cut some irrelevant info off after taking advice from my last post) please tell me
Since you didn't provide a minimal runnable example that we could copy into our IDE, run, and debug, I came up with this example GUI that shows an X shifting to the right.
I used the right arrow key to perform the shift.
Here's the GUI when starting the application.
Here's the GUI after shifting the X three positions.
Here's the GUI after shifting the X four positions.
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Netbeans section.
The first thing I did was start the Swing application by calling the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
Next, I created a JFrame. The JFrame methods must be called in a specific order. This is the order I use for my Swing applications.
I created a main JPanel to hold the array of eight JLabels. I also created an int to hold the position of the X. I used a FlowLayout to lay out the array of JLabels. I( used the Box class to put some space between the JLabels.
As you're creating a more complicated game, create an application model using plain Java getter/setter classes.
I used Key Bindings to bind the right arrow key to the Action class. I used AbstractAction so I'd only have to code the actionPerformed method.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class ShiftRightExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new ShiftRightExample());
}
private int position;
private JLabel[] spotLabel;
public ShiftRightExample() {
this.position = 0;
}
#Override
public void run() {
JFrame frame = new JFrame("Shift Right Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = createMainPanel();
frame.add(mainPanel, BorderLayout.CENTER);
setKeyBindings(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
this.spotLabel = new JLabel[8];
for (int index = 0; index < spotLabel.length; index++) {
spotLabel[index] = new JLabel(" ");
panel.add(spotLabel[index]);
if (index < (spotLabel.length - 1)) {
panel.add(Box.createHorizontalStrut(20));
}
}
updateMainPanel(position, "X");
return panel;
}
private void setKeyBindings(JPanel panel) {
panel.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "shiftRight");
panel.getActionMap().put("shiftRight", new ShiftRightAction());
}
public void updateMainPanel(int position, String value) {
spotLabel[position].setText(value);
}
public class ShiftRightAction extends AbstractAction {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent event) {
updateMainPanel(position, " ");
position++;
position = position % spotLabel.length;
updateMainPanel(position, "X");
}
}
}

Java Swing adding mouse Listener (inner class) for an array of buttons leads to malfunction

Ok, so the program I want to build is simple. There are five buttons named from 0 to 4. If any of the buttons are pressed, then the number 0 to 4 is printed in console.
I have used a GridLayout to place the buttons in the frame. And to set up each button I have created a method, inicializarIG().
This inicializarIG() method creates an array of 5 buttons and inside a for loop it does:
Create an instance of a button for each cell in the array of buttons.
Set up a mouseListener for each button. The value to print in each Listener is different, it is determined by the index of the loop (AND I WANT TO DO IT BY USING THE INDEX!).
Add The button to the main frame.
Surprisingly, This simple program doesn´t work properly. It always print the number "5" no matter what button is pressed:
NOTE: I had to put the index var outside the inicializarIG() method in order to fulfill the var scope for the Listeners. I don't know if the problem is related, just saying in cause it might help.
THE CODE:
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class IGrafica {
private JFrame frame;
public int index=0;
public IGrafica(){
frame = new JFrame();
configureFrame();
inicializarIG();
}
public void configureFrame(){
frame.setBounds(100,100,400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1,5)); //
}
public void inicializarIG(){
//Buttons
JButton [] botones = new JButton [5];
//Loop to set up buttons and add the mouseListener
for (index = 0; index < botones.length; index++) {
botones[index] = new JButton(Integer.toString(index));
//Set up each listener
botones[index].addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println(index);
//texto.setBackground(colores[index]);
}
});
//Add the button
frame.getContentPane().add(botones[index]);
}
}
public void visualizate(){
frame.setVisible(true);
}
public static void main(String[] args) {
IGrafica window = new IGrafica();
EventQueue.invokeLater(new Runnable() {
public void run() {
window.visualizate();
}
});
}
}
Thank you in advance. Any idea will be welcomed.
Jesús
First of all, don't use a MouseListener for this, but rather use an ActionListener, since this works best for buttons. Next of all, you need to remember that your listener is a class of its own, and it needs a variable of its own to store its own index, else it uses the final value of the loop index which is not what you want. Either this or use the ActionEvent's actionCommand property, a value which will match the text of the button. So:
botones[index].addActionListener(new MyActionListener(index));
and
// a private inner class
private class MyActionListener implements ActionListener {
private int index;
public MyActionListener(int index) {
this.index = index;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("index is: " + index);
System.out.println("Action Command is: " + e.getActionCommand());
}
}
Or if you want to use an anonymous inner class:
botones[index].addActionListener(new ActionListener() {
private int myIndex;
{
this.myIndex = index;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("index is: " + myIndex);
}
});

Calculator issue with simple logic

I'm new to Java and have set myself the task of trying to create a simple calculator (and GUI) to advance my understanding and skills of the language.
Take this code:
import java.awt.FlowLayout;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class calc extends JFrame {
public JTextField input;
public JTextField output;
public JPanel Window;
public JButton math_button[] = new JButton[5];
public JButton number_button[] = new JButton[10];
public String[] number_button_name = {"1","2","3","4","5","6","7","8","9","0"};
public String[] name = {"Add", "Mulitply", "Divide", "Subtract", "Equals"};
public JFrame frame = new JFrame();
public JPanel math_panel = new JPanel();
public JPanel number_panel = new JPanel();
public JTextField math_input = new JTextField();
boolean trrgger = false;
thehandler handler = new thehandler();
public void go()
{
for(int b=0; b<number_button.length; b++)
{
number_button[b] = new JButton(number_button_name[b]);
number_button[b].addActionListener(handler);
number_panel.add(number_button[b]);
}
for(int i=0; i<math_button.length;i++)
{
math_button[i] = new JButton(name[i]);
math_button[i].addActionListener(handler);
math_panel.add(math_button[i]);
}
frame.getContentPane().add(BorderLayout.NORTH, math_input);
frame.getContentPane().add(BorderLayout.SOUTH, math_panel);
frame.getContentPane().add(BorderLayout.CENTER, number_panel);
frame.setSize(400,400);
frame.setVisible(true);
}
//Method to handle the math and return the results of whichever 'button' was pressed
static int Math(String button_num, int first_num, int second_num)
{
int total = 0;
if(button_num == "Add")
{
total = first_num + second_num;
}
else if (button_num == "Mulitply") //multiply
{
total = first_num * second_num;
}
else if (button_num == "Divide") //divide
{
total = first_num / second_num;
}
else if (button_num == "Substract") //subtract
{
total = first_num - second_num;
}
else if (button_num == "Equals") //subtract
{
total = total;
}
return total;
}
//Action Events - Code that is triggered once the associated button is clicked
public class thehandler implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
for (int h = 0; h <math_button.length; h++)
{
if(event.getSource()==math_button[h])
{
int firstn = Integer.parseInt(math_input.getText());
math_input.setText("");
int secondn = Integer.parseInt(math_input.getText());
System.out.println(calc.Math(math_button[h].getText(), firstn, secondn));
}
}
for(int n=0; n<number_button.length; n++)
{
if(event.getSource()==number_button[n])
{
String number_clicked = (number_button[n].getText());
String number = math_input.getText();
math_input.setText(number + number_clicked);
}
}
}
}
}
The idea behind this code is to create a simple GUI and allows the user to input the desired amount of numbers and then press the 'equals' button to display the result. However, as stated I'm having a problem with the logic. I can get the first entered number from the JTextField, clear the text once the first variable has been initialized but this is where the program falls over. The variable 'second_num' is passed to the 'Math' method as blank (which throws up errors) because that's what I tell the ActionEvent to do in order to allow for more fluid use of the program, no user wants to have to keep clearing the input box when using a calculator.
Anybody got any ideas?
Thanks
int firstn = Integer.parseInt(math_input.getText());
math_input.setText("");
int secondn = Integer.parseInt(math_input.getText());
What exactly do you expect the above lines to do? You are getting the text from math_input. Then you set it to an empty string. And by immediately getting the string back you are expecting to get something other than empty string?
The correct approach would be:
First time the handler is called (i.e. a "math" button is clicked) collect the input. Store it somewhere.
Next time this handler will be called you will have your next input. And so on until the user clicks on "=" to evaluate the whole expression.
Advice: If you are new to java, you might find it easier to create a calculator on the command line first. The functionality of a calculator does not require a GUI. In command line collecting the input is more simple. If you get that working then you can proceed to more fancy stuff like Swing
I looked at your code but its sound complicated for me. I recommend you to use IDE like Netbeans. Create swing application. To add two number all you need to do is as follow
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
int input_1 = Integer.parseInt(jTextField1.getText());
int input_2 = Integer.parseInt(jTextField2.getText());
jTextField3.setText(String.valueOf((input_1+input_2)));
}
http://i.stack.imgur.com/1G4v7.jpg

How to Check if all the JTexFields are empty or not?

I am using a for loop to create 9 JTextFields and this is working fine. My problem is, I want to check of all the these JTextField is empty or not' at one time. I know there is a method like:
if (textbox.getText().trim().equals(""))
to check if the JTextField is empty or not, But I am not sure if it is suitable for the method that I am using for JTextField. Below is my for loop:
for (int index = 1; index <=9; index++)
{
JTextField field = new JTextField(3);
field.setPreferredSize(new Dimension(150, 50));
field.setHorizontalAlignment(JTextField.CENTER);
field.setEditable(false);
second.add(field);
second.add(Box.createHorizontalStrut(10));
second.add(Box.createVerticalStrut(10));
}
Store your text fields in a List so that you can iterate over them later.
public class ClassContainingTextFields {
private final ArrayList<JTextField> textFields = new ArrayList<>();
// ... inside the method that creates the fields ...
for (int i = 0; i < 9; i++) {
JTextField field = new JTextField(3);
// .. do other setup
textFields.add(field);
}
/**
* This method returns true if and only if all the text fields are empty
**/
public boolean allFieldsEmpty() {
for (JTextField textbox : textFields) {
if (! textbox.getText().trim().isEmpty() ) {
return false; // one field is non-empty, so we can stop immediately
}
}
return true; // every field was empty (or else we'd have stopped earlier)
}
// ....
}
Consider this code.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Test extends JFrame implements ActionListener {
JTextField tfs[];
JButton btn;
public Test(){
setLayout( new FlowLayout());
tfs = new JTextField[9];
for( int i=0; i< tfs.length; i++) {
tfs[i] = new JTextField(10);
add(tfs[i]);
}
add( btn = new JButton("Check"));
btn.addActionListener(this);
setSize(200,300);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed (ActionEvent ae){
boolean pass = true;
for(int i=0; i<tfs.length; i++)
if( tfs[i].getText().trim().equals(""))
pass = false;
System.out.println(pass?"Passed":"Failed");
}
public static void main (String args[]){
new Test();
}
}
How about implementing your own DocumentListener? You could have a Boolean that turns true when all fields are empty, and you could do your various hangman-related checks directly after every change in a fields Document.

Jbutton event handler not working properly

rollDice.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//generate roll
int roll = dice.getRoll();
addGameFeedMessage(players[1].getName() + " rolled " + roll);
//store the player's position before the roll
int currentPlayerPos = players[1].getPosition();
//update player's position
players[1].movePlayer(roll);
//move the player icon to the player's position
tiles[players[1].getPosition()].addIconCurrentPlayersPanel(players[1].getPlayerIcon());
//revalidate components
//tiles[currentPlayerPos].getCurrentPlayersPanel().revalidate();
//tiles[players[1].getPosition()].getCurrentPlayersPanel().revalidate();
//this loop was put in to see if doing revalidate() on all panels would make a difference but the problem is still there
for(int i = 0; i < tiles.length; i++)
{
tiles[i].getCurrentPlayersPanel().revalidate();
}
}
});
Can anyone explain why the for loop in the actionListener for roll dice doesn't seem to work yet the for loop just above it which is the exact same thing works? There's no actual error as such it just doesn't do anything, however it does get inside the actionListener and executes as we've put print statements etc in it.
Guessing its something strange about actionListeners but I'm not sure what.
Any assistance would be appreciated, thankyou.
You should call validate() after the for loop as follows:
for(int i = 0; i < getNumOfPlayers(); i++)
{
currentPlayersOnTile[5].add(players[i].getPlayerIcon());
}
validate();
For Example consider the code given below:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
class DemoPanels extends JFrame
{
public void createAndShowGUI()
{
final JPanel panel = new JPanel();
getContentPane().add(panel);
JButton button = new JButton("Click");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
for (int i = 0 ; i < 10 ; i++ )
{
JPanel panel1 = new JPanel();
panel1.add(new JButton(String.valueOf(i)));
panel.add(panel1);
}
validate();//comment this line and then compile and execute the code to see the effect
}
});
getContentPane().add(button,BorderLayout.SOUTH);
setVisible(true);
setSize(300,400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
DemoPanels dp = new DemoPanels();
dp.createAndShowGUI();
}
});
}
}
NOTE: comment the code validate() and then compile and execute it to see the effect.

Categories