Integer not working with an if statement - java

I am making a text based game, and I am experimenting with different ways of making the storyline of the game progress. (Im sorry if this is semi-hard to follow, I am new to this website, and still fairly new to Java, I'm making this for a class project)
One of the ways I am trying is by increasing a value (In this case LevelNum) by one, and whenever a number not equal to zero is displayed it will set the text of jLabel1 to whatever the text is.
I am trying to do this by using an if statement as shown here:
if(LevelNum == 0) {
jLabel1.setText(StoryData.LevelOne);
}
The increase of LevelNum is done like this:
public void actionPerformed(ActionEvent e) {
LevelNum += 1;
System.out.println(LevelNum);
}
(The System.out was just to check to see if it was increasing the number)
The problem I am running into is that no matter what the value of jLabel1 is, the text never changes, and I dont know why.
The whole code can be found here: https://pastebin.com/JSX6urFT
The StoryData is a seperate class within in my text document, and the individual strings look like this: static String LevelOne = "Level one test";
Here is all the code related to LevelNum:
public class DemoGUI extends javax.swing.JFrame {
private static int LevelNumBackUp = 0;
private static int LevelNum = 0;
public JTextArea jLabel1;
public JTextField jText1;
public JButton jButton1;
public JButton jButton2;
public JButton jButton3;
public JButton jButton4;
public JButton jButtonStart;
public JTextArea jTextAreaStart;
public JButton jButtonCredits;
public JButton jButtonReturn;
public static void main(String[] args) {
int LevelNum = 0;
int LevelNumBackUp = 0;

Keep level changing code in actionPerformed.
Try this:
public void actionPerformed(ActionEvent e) {
LevelNum += 1;
System.out.println(LevelNum);
// Introduction
if (LevelNum == 1) {
jLabel1.setText("level1");
}
if (LevelNum == 2) {
jLabel1.setText("level2");
}
if (LevelNum == 3) {
jLabel1.setText("level3");
}
}

After the value of the label changed, try to call revalidate() and repaint() to update your Userinterface

Looking at the full code, the part which increments LevelNum is in the following block:
jButton3.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
LevelNum += 1;
System.out.println(LevelNum);
}
});
Then, down below, you have this code:
if(LevelNum == 1) {
jLabel1.setText(StoryData.LevelOne);
}
Let's walk through the code the way a computer would. When we get to that first block, we add a new ActionListener. However, we do not execute the actionPerformed method immediately, so LevelNum is still what it was previously. Later on, we get to the if statement, but LevelNum has not been incremented.
When the ActionListener is triggered, and the actionPerformed method executes, it increments LevelNum and then prints the new LevelNum, but it does NOT change jLabel1 because there is no code telling it to do so.
It looks like what you want to do is update jLabel1 inside the actionPerformed method.

Related

Why is my boolean value preemptively being returned?

I am working on a login validator and have a class that checks username and password validity. After checking, a boolean variable (isValidLoginCredentials) is updated in the LoginProxy class, which can be fetched by a get method and used for another purpose. However, the value that is returned by the get method is always the default value that I assigned to isValidLoginCredentials when the class was created. I think the issue is that I am calling the getter method in main() before I have a chance to update isValidLoginCredentials, but I don't understand what changes I should make to stop this. Here is the relevant part of the class and main program.
public class LoginProxy implements ActionListener
{
private JLabel usernameLabel;
private JTextField usernameText;
private JLabel passwordLabel;
private JPasswordField passwordText;
private JButton loginButton;
private boolean isValidLoginCredentials = false;
public void createLogin()
{
/*Here was code irrelevant to the problem I removed*/
loginButton.addActionListener(new LoginProxy());
loginButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String user = usernameText.getText();//get the username
String pass = passwordText.getText();//get the password
String credentials = user +":"+pass;//creates the string I compare to other valid
//credentials
ConcreteLoginValidator validator = new ConcreteLoginValidator(credentials);
try
{
isValidLoginCredentials = validator.checkLogin();
System.out.println("The credentials are "+isValidLoginCredentials);
}
catch (FileNotFoundException e1)
{
e1.printStackTrace();
}
}
});
}
public void actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
}
public boolean getValidity()
{
return isValidLoginCredentials;
}
And here is the main method
public static void main(String[] args)
{
boolean isValidLogin = false;
LoginProxy proxy = new LoginProxy();
proxy.createLogin();
isValidLogin = proxy.getValidity();
if(isValidLogin == true)
{
JFrame frame = MainUI.getInstance();
frame.setSize(900, 600);
frame.pack();
frame.setVisible(true);
}
}
What should I add so that isValidLogin=proxy.getValidity(); returns a value only after I have already entered and checked whether the login credentials are correct?
Going straight to the point, a quick fix is to put the code below:
if(isValidLoginCredentials) {
JFrame frame = MainUI.getInstance();
frame.setSize(900, 600);
frame.pack();
frame.setVisible(true);
}
After this part:
System.out.println("The credentials are "+isValidLoginCredentials);
The code you call on createLogin() just sets the action listener to the button in the UI, hence the code will be executed just when you click on the button.
On the top of that, when you open a window, it starts a separated thread. I don't know the rest of the code, but assuming that when you instantiate the LoginProxy, it opens the login window. But the way you wrote, it will open the window and check the isValidLogin straight away (it doesn't wait you to click the button).
If you want to prove that, you can simply put a System.out.println before and after the proxy.createLogin(). You will realise that both lines will be reached while the UI is rendered.
Using a modal dialog that blocks until it is closed.
Very simplified example:
public class Dialog { // LoginProxy in questions code
private String value = null;
public void show(Window owner) {
var dialog = new JDialog(owner, JDialog.DEFAULT_MODALITY_TYPE);
var field = new JTextField(40);
var okButton = new JButton("OK");
okButton.addActionListener(ev -> {
value = field.getText();
dialog.dispose();
});
var panel = new JPanel();
panel.add(field);
panel.add(okButton);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(owner);
dialog.setVisible(true); // this will be blocked until JDialog is closed
}
public String getValue() {
return value;
}
}
called like
public static void main(String[] args) {
var dialog = new Dialog();
dialog.show(null);
System.out.println(dialog.getValue()); // check if valid and open JFrame in questions code
}
Advantage of this solution IMHO: the dialog class (LoginProxy) does not need to know about the main class and main JFrame. It has a clear single function: ask for user input.
the dialog creation is even easier using JOptionPane
In order to guarantee reading a value written in another thread, you must make the field volatile:
private volatile boolean isValidLoginCredentials;
You must also wait until the other completes before reading it. That aspect I leave to the reader.

JAVA ActionListener for every button

im trying to make simple calculator in java GUI. I got to the point where I can clearly see that code is just ugly because of repeating functions like:
number0 = new JButton("0");
number0.setBounds(130, 280, 50, 50);
add(number0);
number0.addActionListener(new GetNumber0());
public class GetNumber0 implements ActionListener {
public void actionPerformed(ActionEvent e) {
String text =number0.getText();
int num = Integer.parseInt(text);
result=(result*10)+num; // +num if else than 0
lResult.setText("Result: "+result);
}
}
Which I'm doing for every button, so is there a way to make this code look better? I'm hoping for something that can get a variable from each button individually and use it in only one fucntion named GetNumber().
You don't need to create a separate listener, and you really shouldn't. It's not useful to write String text = number0.getText(); because you already know it's going to be 0.
Share the ActionListener between the buttons.
public class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
int num = Integer.parseInt(btn.getText());
result=(result*10)+num;
lResult.setText("Result: "+result);
}
}

Java Swing button actionEvent

sorry to bother everyone.
Overall problem: I'm trying to open a dialogue box let the user enter something then close it
Issue: - A function is not being called (i think)
- The main problem is when i use debug it works fine so Its difficult for me to track down the problem
I'm having trouble with JButtons,
it works in debug but not in normal run. this was probably because i was using an infinite loop. someone online suggested i used SwingUtilities but that didn't work (at least i don't think.
/**
*
* #author Deep_Net_Backup
*/
public class butonTest extends JFrame {
String name;
boolean hasValue;
//name things
private JLabel m_nameLabel;
private JTextField m_name;
//panel
private JPanel pane;
//button
private JButton m_submit;
//action listener for the button submit
class submitListen implements ActionListener {
public void actionPerformed(ActionEvent e) {
submit();
System.out.println("Test");
}
}
//constructor
public butonTest(){
//normal values
name = null;
hasValue = false;
//create the defauts
m_nameLabel = new JLabel("Name:");
m_name = new JTextField(25);
pane = new JPanel();
m_submit = new JButton("Submit");
m_submit.addActionListener(new submitListen());
//
setTitle("Create Cat");
setSize(300,200);
setResizable(false);
//add components
pane.add(m_nameLabel);
pane.add(m_name);
pane.add(m_submit);
add(pane);
//last things
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
//submit
private void submit()
{
System.out.println("submit");
name = m_name.getText();
hasValue = true;
}
//hasValue
public boolean hasValue()
{
return(hasValue);
}
//get the text name
public String getName()
{
return(name);
}
public void close()
{
setVisible(false);
dispose();
}
public static void main(String[] args)
{
/* Test 1
boolean run = true;
String ret = new String();
butonTest lol = new butonTest();
while(run)
{
if(lol.hasValue())
{
System.out.println("Done");
run = false;
ret = new String(lol.getName());
lol.close();
}
}
System.out.println(ret);*/
//Tset 2
/*
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
butonTest lol = new butonTest();
if(lol.hasValue())
{
System.out.println(lol.getName());
}
}
});*/
}
}
Edit:
How its not working: When i run Test the program will print test and submit then it should change the hasValue to true. this will (hopefully) allow the if statement to run to print done. This does not happen.
Edit 2:
I have just added a few more lines for further testing 2 prints and this seems to have solved the issue (but this is bad)
System.out.println("hasValue " + hasValue); -> to the hasValue() function
System.out.println("set to true"); -> submit() function
You are doing something far too complicated than is necessary. Instead of having the listener as a seperate class, you could have it as an anonymous class. That way you can get a handle on the outer class (butonTest.this), and call any method you want on it.
m_submit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
submit();
System.out.println("Test");
butonTest.this.close();
}
});
I'm not sure what you are trying to do with the infinite loop. It would have run to completion before you show the dialog anyway.
It would help to read up a bit on how Event-Handling works in Swing :)
I am afraid your constructor butonTest() and submit() method are out of your
class (public class butonTest extends JFrame).
you need to get them inside your class:

Java - Separate Listener Class throws NullPointerException

Apologize for the long post, but I wanted to be as detailed as possible so there's a better chance people understand what I'm trying to convey:
OK, so an overview of this problem is that I'm trying to make a program that simulates a cash register. (This is a "for-fun" project). The way I set it up is:
CashRegister: main class that starts the program, serves as the main window for everything.
public class CashRegister extends JFrame {
...
}
Other classes: serve as JPanels that provide the different components of the main CashRegister window. Example:
public class NorthPanel extends JPanel {
...
}
Then in the CashRegister class:
add(new NorthPanel(), BorderLayout.NORTH);
etc.
Basically, I have a JTextField in the NorthPanel class called priceField that holds the value of the price the user enters. I have a separate class (Keypad) that also extends JPanel and serves as the number keypad in the center of the main window. In CashRegister:
add(new NorthPanel(), BorderLayout.NORTH);
add(new Keypad()); // (default for BorderLayout is CENTER)
One of the problems I have run into is that I created one class, EventHandler, to serve as the listener class for the entire program because there are components in each JPanel class (NorthPanel and Keypad, for instance) that need to communicate with each other; the user presses a keypad button, the price field in the NorthPanel needs to know what key in the keypad was pressed.
I don't know if the problem comes from the fact that these components are coming from different classes and are therefore referenced differently, or what. All the classes are in the same directory, I'm using NetBeans and it's all part of the same package.
In my EventHandler class, I created several different constructors so as to be able to pass in all the components that need to communicate with each other from different classes. For example:
public class EventHandler implements ActionListener {
private JTextField priceField;
private JButton[][] keypad;
public EventHandler(JTextField priceField) {
this.priceField = priceField;
}
public EventHandler(JButton[][] keypad) {
this.keypad = keypad;
}
}
In my NorthPanel class, I instantiate priceField first, configure it (set the font, etc.) and say:
EventHandler e = new EventHandler(priceField);
in my attempt to pass the priceField through to my listener class.
Then in the Keypad class, I say:
EventHandler e = new EventHandler(keypad);
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 3; j++) {
keypad[i][j].addActionListener(e);
}
}
Then in the EventHandler class, having passed through those variables:
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 3; j++) {
if(keypad[i][j] == e.getSource()) {
// call a custom method to append the numbers to the text field
}
}
}
}
It is at this point that I get a NullPointerException. I don't know why, but my guess is that it's because the listener objects are coming from different classes and using different constructors because I have to pass in different objects from each class that need to communicate with each other. I'm not 100% sure though. Is there a way to get around this or am I doing something completely wrong?
You should let the CashRegister handle all user input, as it is the main Frame of your application (it extends the JFrame). For the sub-panels, make a method, such as aKeyWasPressed( int keyCode ), that will be called from your frame, within the body of keyPressed method you override.
Also, set the JFrame to be focusable, and preferably make the other panels unfocusable setFocusable(false);
Here is a sample code of the CashRegister:
public class CashRegister extends JFrame implements KeyListener
{
private NorthPanel northPanel;
private Keypad keypad;
public CashRegister ()
{
this.setFocusable(true);
this.addKeyListener(this);
northPanel = new NorthPanel();
keypad = new Keypad();
/* Your code ... */
}
#Override
public void keyTyped(KeyEvent ke)
{
/*Do nothing*/
}
#Override
public void keyPressed(KeyEvent ke)
{
northPanel.aKeyWasPressed( ke.getKeyCode() );
keypad.aKeyWasPressed( ke.getKeyCode() );
}
#Override
public void keyReleased(KeyEvent ke)
{
/*Do nothing*/
}
}
Note: To distinguish which key was pressed, inside the aKeyWasPressed method from your panels, you can do:
private void aKeyWasPressed(int code)
{
if(code == KeyEvent.VK_A)
{
/*If its letter 'A', do this...*/
}
}
Again, there are many ways of doing it, but letting the Frame itself handle all user input is, in my opinion, the best pratice in most cases, mainly when dealing with multiple panels.

action listener in another class - java

it is possible to have two class, and in one something like
arrayButtons[i][j].addActionListener(actionListner);
and in another
ActionListener actionListner = new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int j = 0; j < arrayButtons.length; j++) {
for (int i = 0; i < arrayButtons[j].length; i++) {
if (arrayButtons[j][i] == e.getSource()) {
if ((gameNumber == 2) && (playHand.getNumberOfCards() == 0)) {
if (player[j].getCard(i).getSuit() == Suit.HEARTS.toString() && player[j].hasSuitBesideHearts())
//second game
messageOnTable("xxx");
else{
arrayButtons[j][i].setVisible(false);
test[j].setIcon(player[j].getCard(i).getImage());
pnCardNumber[j].setText(Integer.toString(player[j].getCard(i).getNumber()));
pnCardName[j].setText(player[j].getCard(i).toString());
pnCardSuit[j].setText(player[j].getCard(i).getSuit());
playHand.addCard(player[j].getCard(i), j);
player[j].removeCard(i);
}
}
}
//and more
the reason of that is because i need to separate the button (swing) to the action listener
how i can do ?
thanks
Not only it is possible to separate these two, it's also recommended (see MVC pattern - it's very much about separating screen controls like buttons, and the logics of your program)
The easiest way that comes to my mind is to do write a named class that implements ActionListener interface, something like this:
public class SomeActionListener implements ActionListener{
private JTextField textField1;
private JComboBox combo1;
private JTextField textField2;
//...
public SomeActionListener(JTextField textField1, JComboBox combo1,
JTextField textField2){
this.textField1=textField1;
this.combo1=combo1;
this.textField2=textField2;
//...
}
public void actionPerformed(ActionEvent e) {
//cmd
}
}
And then add it to your buttons:
ActionListener actionListener = new SomeActionListener(textField1, combo1, textField2);
someButton.addActionListener(actionListener);
To answer: "my problem is that action listener have many variables of swing like buttons for example,so, when i change to another class, i have problems with that"
Your action listener class could have a constructor that takes a parameter of the type of the view class:
public class Listener implements ActionListener {
private final MyViewClass mView;
public Listener(MyViewClass pView) {
mView = pView;
}
public void actionPerformed(ActionEvent e) {
// can use mView to get access to your components.
mView.get...().doStuff...
}
}
Then in your view:
Listener l = new Listener(this);
button.addActionListener(l);
you can do it easily by using nested classes,
but i think the best way is pass the parent object as a parameter to the construct of object and using it as an action handler;
//**parent class - Calculator **//
public class Calculator extends JFrame implements ActionListener{
private DPanel dPanel;
private JTextField resultText;
public Calculator(){
// set calc layout
this.setLayout(new BorderLayout(1,1));
dPanel = new DPanel(this); // here is the trick ;)
}
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
resultText.setText(command);
// **** your code ****/
}
}
//**inner class - DPanel**//
public class DPanel extends JPanel{
private JButton digitsButton[];
private JButton dotButton,eqButton;
public DPanel(Calculator parent){
//layout
this.setLayout(new GridLayout(4,3,1,1));
// digits buttons
digitsButton = new JButton[10];
for (int i=9;i>=0;i--){
digitsButton[i] = new JButton(i+"");
digitsButton[i].addActionListener(parent); // using parent as action handler ;)
this.add(digitsButton[i]);
}
}
}
It's a bit off topic but you should definately not use the == operator to compare Strings as you appear to be doing on this line:
if (player[j].getCard(i).getSuit() == Suit.HEARTS.toString()
This is because Strings are pointers, not actual values, and you may get unexpected behaviour using the == operator. Use the someString.equals(otherString) method instead. And also
"String to compare".equals(stringVariable)
is alot better than the other way around
stringVariable.equals("String to compare to")
because in the first example you avoid getting a NullPointerException if stringVariable is null. It just returns false.
Yes, it can be done. It's very simple; in one class you have your buttons, in the other class you just need to implement an ActionListener and just make your //cmd
to separate that button's function. To do this, you need to use e.getActionCommand().equals(buttonActionCommand).
Sample code:
public class Click implements ActionListener{
public Click(
//input params if needed
){
}
public void actionPerformed(ActionEvent e) {
if( e.getActionCommand().equals(buttonActionCommand){
//cmd
}
}
}
To add that listener on your button just do:
buttonTest.addActionListener(new Click());

Categories