Issues with GUI on a permutation/combination calculator - java

I was able to program this, and I don't have any errors that I can see, and it even displays the gui. I'm pretty sure I assigned the buttons properly. But the GUI is temperamental, and when I run it, it displays but sometimes the insides of the gui disappear when I enter values. But it calculates nCr, just not pCr.
I have a driver class. Pretty sure it's implemented properly. Here's my panel class. I'm wondering what's wrong and why the GUI doesn't function properly
I realize this is a lot of code. I'm not expecting anyone to rewrite this for me. I just want to know what I'm doing wrong, and how I can go about correcting it.
Thanks.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.Color;
import javax.swing.JOptionPane;
public class PermCombCalc extends JPanel {
JButton permButton = new JButton();
JButton combButton = new JButton();
JButton clearButton = new JButton();
JTextField npermField = new JTextField();
JTextField rperField = new JTextField();
JTextField nchooseField = new JTextField();
JTextField rchooseField = new JTextField();
JTextField pAnswerField = new JTextField();
JTextField cAnswerField = new JTextField();
public PermCombCalc() {
setLayout(new BorderLayout());
setPreferredSize(new Dimension(1000, 700));
JLabel permLabel = new JLabel("Permutation:");
permLabel.setBounds(10, 20, 100, 20);
permLabel.setForeground(Color.BLACK);
add(permLabel);
JLabel combLabel = new JLabel("Combination:");
combLabel.setBounds(215, 20, 75, 20);
combLabel.setForeground(Color.BLACK);
add(combLabel);
// Creating Permutation Button
JLabel PnrLabel = new JLabel("P (n,r)");
PnrLabel.setForeground(Color.black);
permButton.setBounds(10, 115, 100, 25);
add(permButton);
permButton.add(PnrLabel);
// Action Listener for permbutton
permButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
permButton.setActionCommand("Perm");
permButton.addActionListener(new ButtonListener());
}
});
// Creating combination button
JLabel CnrLabel = new JLabel("C(n, r)");
CnrLabel.setForeground(Color.black);
combButton.setBounds(190, 115, 100, 25);
add(combButton);
combButton.add(CnrLabel);
// ActionListener
combButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
combButton.setActionCommand("comb");
combButton.addActionListener(new ButtonListener());
}
});
// Text fields for n and r
npermField.setBounds(23, 50, 60, 20);
add(npermField);
nchooseField.setBounds(230, 50, 60, 20);
add(nchooseField);
rperField.setBounds(23, 80, 60, 20);
add(rperField);
rchooseField.setBounds(230, 80, 60, 20);
add(rchooseField);
// Input fields
JLabel npLabel = new JLabel("n:");
npLabel.setForeground(Color.black);
npLabel.setBounds(10, 55, 10, 10);
add(npLabel);
JLabel ncLabel = new JLabel("n:");
ncLabel.setForeground(Color.BLACK);
ncLabel.setBounds(217, 55, 10, 10);
add(ncLabel);
JLabel rpLabel = new JLabel("r:");
rpLabel.setForeground(Color.BLACK);
rpLabel.setBounds(10, 85, 10, 10);
add(rpLabel);
JLabel rcLabel = new JLabel("r:");
rcLabel.setForeground(Color.BLACK);
rcLabel.setBounds(217, 85, 10, 10);
add(rcLabel);
// Fields for answers
JLabel pAnswerJLabel = new JLabel("<-Answers->");
pAnswerJLabel.setForeground(Color.BLACK);
pAnswerJLabel.setBounds(115, 155, 74, 10);
add(pAnswerJLabel);
pAnswerField.setBounds(10, 150, 100, 20);
add(pAnswerField);
cAnswerField.setBounds(190, 150, 100, 20); // where is this field?!
add(cAnswerField);
// Buttons
//clearButton.setBounds(10, 210, 110, 25);
//add(clearButton);
//JLabel clearLabel = new JLabel("Clear Fields");
//clearLabel.setForeground(Color.BLACK);
//clearButton.add(clearLabel);
// clearButton.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// clearButton.setActionCommand("Clear");
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("perm")) {
// contentPane.setBackground(Color.red);
long Pnr = Permutation();
if (Pnr != 0) {
pAnswerField.setText(Pnr + "");
}
} else if (e.getActionCommand().equals("comb")) {
// contentPane.setBackground(Color.black);
long Cnr = Combination();
if (Cnr != 0) {
cAnswerField.setText(Cnr + "");
}
} else if (e.getActionCommand().equals("Clear")) {
// contentPane.setBackground(Color.lightGray);
npermField.setText(null);
rperField.setText(null);
pAnswerField.setText(null);
nchooseField.setText(null);
rchooseField.setText(null);
cAnswerField.setText(null);
}
}
public long Permutation() {
String npString = npermField.getText();
String rpString = rperField.getText();
int npint = 0;
int rpint = 0;
try {
npint = Integer.parseInt(npString);
rpint = Integer.parseInt(rpString);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"ERROR! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (npint <= 0 || rpint <= 0) {
JOptionPane.showMessageDialog(null,"ERROR! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (npint < rpint) {
JOptionPane.showMessageDialog(null,"ERROR! The value of 'r' must be less than \n or equal to the value of 'n.'");
return 0;
}
long Pnr = 1;
int mult = npint;
int nmr = (npint - rpint);
while (mult > nmr) {
Pnr = Pnr * mult;
mult--;
}
return Pnr;
}
public long Combination() {
String ncString = nchooseField.getText();
String rcString = rchooseField.getText();
int ncint = 0;
int rcint = 0;
try {
ncint = Integer.parseInt(ncString);
rcint = Integer.parseInt(rcString);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"ERROR! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (ncint <= 0 || rcint <= 0) {
JOptionPane.showMessageDialog(null,"Error! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (ncint < rcint) {
JOptionPane.showMessageDialog(null,"ERROR! The value of 'r' must be less than \n or equal to the value of 'n.'");
return 0;
}
long nfact = 1;
for (int i = 2; i <= ncint; i++) {
nfact = nfact * i;
}
long rfact = 1;
for (int i = 2; i <= rcint; i++) {
rfact = rfact * i;
}
long nmr = ncint - rcint;
int nmrfact = 1;
for (int i = 2; i <= nmr; i++) {
nmrfact = nmrfact * i;
}
long Cnr = (nfact / (rfact * nmrfact));
return Cnr;
}
}
}

You are using BorderLayout, but you aren't actually specifying the placements of your components, so they are being rendered in unexpected places.
Here is a screenshot of your application with an orange border around pAnswerField and a red border around cAnswerField
You should take a look at the A Visual Guide to Layout Managers for help on using the Layout Managers properly.
For your application, GridLayout is probably a resonable balance between complexity and layout flexibility
GridBagLayout or SpringLayout will give you the most flexibility, but they can be frustratingly complex to work with.
EDIT Another minor problem which is causing the permButton to misbehave.
In your button creation code you have:
permButton.setActionCommand("Perm");
In your action listener you have: if (e.getActionCommand().equals("perm"))
As written your ActionListener will never get invoked when permButton gets pressed... Either switch to equalsIgnoreCase or define a constant rather than using string literals.
I find adding colored borders to be very helpful when doing layout work. Here's a quick example of how to do this:
npermField.setBounds(23, 50, 60, 20);
add(npermField);
nchooseField.setBounds(230, 50, 60, 20);
// add a border to make the component easier to see during layout.
npermField.setBorder(BorderFactory.createLineBorder(Color.ORANGE));
add(nchooseField);

If you like your ButtonListener class the way it is (I don't; will comment about it after the main issue), you can simply reword the buttons' setup:
.
.
.
add(permButton);
permButton.add(PnrLabel);
// Action Listener for permbutton
permButton.setActionCommand("Perm");
permButton.addActionListener(new ButtonListener());
.
.
.
(and likewise for the other buttons).
See? There is no need to add an ActionListener more than once AND also no need to add an ActionListener in order to add the real ActionListener.
The way your application was:
it didn't work on the first button press (since only then the correct listener is set up);
after the first button press, each new press would add another listener, eventually producing unexpected results (I didn't analyzed it thoroughly, and frankly I will not).
About the ButtonListener
Roughly speaking, your class does:
if (typeA) {
doActionA();
} else if (typeB) {
doActionB();
} else if (typeC) {
doActionC();
}
You could simply create 3 separate ActionListeners, each doing just one thing (either doActionA(), or B or C), without ifs. Then set up each button with only the appropriate ActionListener. This way you could also remove the lines setActionCommand(type);, since they would become useless.

Related

Calculator Clear button functionality isn't working as desired. set to 0 causes multiplication to = 0 . Desire AC to give same result as new start ups

//*****
I stripped down as much as I thought possible while still being pleasing to use. this is my beginner calulator project. it shows result as I type. I'm using multiple textFields to achieve this. I'm open to smarter ways. for now though I would like to lie in my bed as I've made it to learn.
On fresh start up no issues with parsing and the getting a result but after clear lets say I used addButton last it will automatically add the first new number to itself then give me the result as the new num1. if I set num1 to 0; add works but not multiplication because of zero... is .setText(" "); really deleting the values? is there a better way? I've read all I could find on textFields.
I will happily take direction to the correct reading material in lieu of a direct answer. textField numbered slightly out of order. My apologies order is top down - 3 -2 -1 -4 -5. 4 and 5 are to help me visualize the problem 3 shows the work, 2 the result and 1 is used for parsing num1 and setting the current result to num1 so I can chain the addition.
I've tried parsing at different locations setting num1 to 0 setting result to the remainder of result and num1 to be the new num2.. and a bunch of other silly attempts at similar solulutions. I know that my if(numberButtons[i]) { statement directly above the switch for + - * / where it sets num2=Double.parseDouble(textField4.getText()); is the main cause but it is also the only way I know to give constant results as I type in my numbers.
I,ve tried more thought-out and many more arbitrary changes to my code trying to understand what's really going on and what's possible.
Afer 3 weeks I am embarrassed for myself. Thank you for your time. Again even just the right direction will help me very much. I do like and desire to solve the problem on my own. I am just truly out of my depth as I am 3 months into this a few hours a day in my time off of work. I truly enjoy it and would love to have a sense of closure and completion to this problem.
///*************
package test;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.border.SoftBevelBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Calc1 implements ActionListener {
JFrame frame;
JTextField textField3,textField2,textField1,textField4,textField5;
JButton[] numberButtons = new JButton[10];
JButton[] functionButtons = new JButton[6];
JButton addButton,subButton,multiButton,diviButton,decimalButton;
JButton equalButton,deleteButton,clearButton,negativeButton;
JPanel panel;
JLabel label;
Font myFont = new Font("Monospaced", Font.BOLD,31);
Font font1 = new Font("Monospaced", Font.BOLD, 30);
Font font2 = new Font("Monospaced", Font.BOLD, 28);
Font font3 = new Font("SansSerif", Font.BOLD, 48);
Font font4 = new Font("Monospaced", Font.BOLD, 65);
double num1=0,num2=0,result=0;
char operator;
Calc1(){
Border border1 = new LineBorder(Color.DARK_GRAY, 4, true);
frame = new JFrame("Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setOpacity(1);
frame.setVisible(true);
frame.setBounds(201, 60, 323, 700);
label = new JLabel();
label.setBounds(5, 4, 300, 52);
label.setFont(font1);
label.setVisible(true);
label.setText("Calculator");
label.setForeground(Color.blue);
label.setFont(new Font("Console", 1, 17));
label.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
Border border = new LineBorder(Color.LIGHT_GRAY, 7, true);
textField3 = new JTextField();
textField3.setBounds(5,54, 299, 38);
textField3.setFont(font2);
textField3.setBackground(Color.lightGray);
textField3.setBorder(border);
textField3.setOpaque(true);
textField3.setHorizontalAlignment(JTextField.RIGHT);
textField3.setFocusable(true);
textField2 = new JTextField();
textField2.setBounds(5, 89, 299, 44);
textField2.setFont(myFont);
textField2.setBackground(Color.lightGray);
textField2.setBorder(border);
textField2.setVisible(true);
textField2.setOpaque(true);
textField2.setHorizontalAlignment(JTextField.RIGHT);
textField2.setFocusable(false);
textField1 = new JTextField();
textField1.setBounds(5,510, 300, 35);
textField1.setFont(myFont);
textField1.setVisible(true);
textField4 = new JTextField();
textField4.setBounds(5,549, 300, 35);
textField4.setFont(myFont);
textField4.setVisible(true);
textField5 = new JTextField();
textField5.setBounds(5,580, 300, 35);
textField5.setFont(myFont);
textField5.setVisible(true);
addButton = new JButton("+");
subButton = new JButton("-");
multiButton = new JButton("x");
diviButton = new JButton("÷");
decimalButton = new JButton(".");
equalButton = new JButton("=");
deleteButton = new JButton("←");
clearButton = new JButton("AC");
functionButtons[0] = addButton;
functionButtons[1] = subButton;
functionButtons[2] = multiButton;
functionButtons[3] = diviButton;
functionButtons[4] = decimalButton;
functionButtons[5] = clearButton;
for(int i=0; i<6; i++) {
functionButtons[i].addActionListener(this);
functionButtons[i].setFont(myFont);
functionButtons[i].setFocusable(false);
functionButtons[i].setBorder(new SoftBevelBorder(BevelBorder.RAISED));
}
for(int i=0; i<10; i++) {
numberButtons[i] = new JButton(String.valueOf(i));
numberButtons[i].addActionListener(this);
numberButtons[i].setFont(font2);
numberButtons[i].setFocusable(false);
}
panel = new JPanel();
panel.setLayout(new GridLayout(4,4,4,4));
panel.add(label);
panel.setBackground(Color.DARK_GRAY);
panel.setForeground(Color.BLACK);
panel.setVisible(true);
panel.setOpaque(true);
panel.setBorder(border1);
panel.setBounds(4, 133, 300, 300);
panel.add(numberButtons[7]);
panel.add(numberButtons[8]);
panel.add(numberButtons[9]);
panel.add(addButton);
panel.add(numberButtons[4]);
panel.add(numberButtons[5]);
panel.add(numberButtons[6]);
panel.add(subButton);
panel.add(numberButtons[1]);
panel.add(numberButtons[2]);
panel.add(numberButtons[3]);
panel.add(multiButton);
panel.add(decimalButton);
panel.add(numberButtons[0]);
panel.add(clearButton);
panel.add(diviButton);
frame.add(panel);
frame.add(label);
frame.add(textField3);
frame.add(textField2);
frame.add(textField1);
frame.add(textField4);
frame.add(textField5);
frame.setOpacity(1);
frame.setForeground(Color.BLACK);
frame.setBackground(Color.BLACK);
frame.setVisible(true);
label.setForeground(Color.blue);
label.setBackground(Color.GRAY);
label.setOpaque(true);
}
public static void main(String[] args) {
Calc1 calc = new Calc1();
}
public void actionPerformed(ActionEvent e) {
for(int i=0; i<10; i++) {
if(e.getSource() == numberButtons[i]) {
textField1.setText(textField1.getText().concat(String.valueOf((i))));
textField3.setText(textField3.getText().concat(String.valueOf((i))));
textField4.setText(textField4.getText().concat(String.valueOf((i))));
textField5.setText(textField5.getText().concat(String.valueOf((i))));
}
}
if (e.getSource()==subButton) {
num1=Double.parseDouble(textField1.getText());
operator='-';
textField3.setText(textField3.getText().concat("-"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
if (e.getSource()==addButton) {
num1 = Double.parseDouble(textField1.getText());
operator = '+';
textField3.setText(textField3.getText().concat("+"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
if (e.getSource()==multiButton) {
num1 = Double.parseDouble(textField1.getText());
operator = '*';
textField3.setText(textField3.getText().concat("x"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
if (e.getSource()==diviButton) {
num1 = Double.parseDouble(textField1.getText());
operator = '/';
textField3.setText(textField3.getText().concat("÷"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
for(int i=0; i<10; i++) {
if(e.getSource()==numberButtons[i]) {
num2=Double.parseDouble(textField4.getText());
switch(operator) {
case'-':
result=num1-num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
case'+':
result=num1+num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
case'*':
result=num1*num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
case'/':
result=num1/num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
}
}
textField2.setText(String.valueOf((result)));
}
if (e.getSource()==clearButton) {
textField3.setText("");
textField2.setText("");
textField1.setText("");
textField4.setText("");
textField5.setText("");
}
}
}
Where you clear all your JTextFields, You should also reset all member variables used in previous calculations. After all, beacause of their scope (class global), they will still be holding values unless reset:
if (e.getSource() == clearButton) {
textField3.setText("");
textField2.setText("");
textField1.setText("");
textField4.setText("");
textField5.setText("");
num1 = 0;
num2 = 0;
result = 0;
operator = '\0';
}

How to change the value of a boolean from false to true using a button

I made a boolean for my while loop to make it run when the boolean is equal to true, I wanted to make the play button make the boolean = true which would trigger the while loop and run the game. But this isn't working for some reason.
Can someone help with making the boolean gameRunning = true;? I just can't figure out how to change its value from false to true.
I tried using atomic booleans but that didn't work
package panda.org;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.lang.Math;
import java.util.concurrent.atomic.AtomicBoolean;
public class NumberGame implements ActionListener{
JFrame frame;
JLabel rules;
JLabel rulesText;
JLabel rulesText2;
JButton play;
JButton exit;
Font myFont = new Font("Serif Plain", Font.BOLD, 15);
NumberGame() {
frame = new JFrame("NumberGame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 500);
frame.setLocationRelativeTo(null);
frame.setLayout(null);
frame.setResizable(true);
Image icon = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Gaming MSI\\Pictures\\Saved Pictures\\download (1).png");
frame.setIconImage(icon);
rules = new JLabel("Rules: ");
rules.setFont(myFont);
rules.setBounds(50, 100, 100, 75);
rulesText = new JLabel("We will pick a random number in the range of 1 -> 50.");
rulesText.setBounds(100, 100, 315, 75);
rulesText2 = new JLabel("Your job is to guess that number!");
rulesText2.setBounds(100, 120, 315, 75);
play = new JButton("Play");
play.setBounds(150, 300, 100, 75);
boolean gameRunning = false;
play.addActionListener(e -> {
gameRunning = true;
});
while(gameRunning = true) {
JLabel label = new JLabel("Guess the number from 1 till 50");
label.setFont(myFont);
label.setBounds(150, 75, 315, 75);
JLabel hints = new JLabel("");
hints.setBounds(150, 180, 1000, 100);
JLabel hints2 = new JLabel("");
hints2.setBounds(150, 200, 1000, 100);
JTextField text = new JTextField();
text.setBounds(250, 150, 100, 25);
JButton check = new JButton("Check");
check.setBounds(150, 150, 75, 25);
double randomDouble = Math.random();
randomDouble = randomDouble * 50 + 1;
double randomDouble2 = Math.random();
randomDouble2 = randomDouble2 * (15 - 5 + 1) + 5 ;
double randomDouble3 = Math.random();
randomDouble3 = randomDouble3 * (15 - 5 + 1) + 5 ;
int randomHint = (int) randomDouble2;
int randomHint2 = (int) randomDouble3;
int randomInt = (int) randomDouble;
System.out.println("nb: " + randomInt);
System.out.println("hint: " + randomHint);
System.out.println("hint2: " + randomHint2);
JLabel status = new JLabel("");
status.setBounds(150, 160, 1000, 100);
JLabel closeness = new JLabel("");
closeness.setBounds(150, 220, 1000, 100);
closeness.setForeground(Color.blue);
final int[] failedAttempts = {0};
check.addActionListener(e1 -> {
String nb = text.getText();
int change = Integer.parseInt(nb);
frame.add(status);
if (randomInt == change) {
status.setText("You chose the correct number!");
status.setForeground(Color.green);
hints.setText("");
hints2.setText("");
}
if (randomInt > change) {
closeness.setText("Your answer is smaller than the correct answer");
}
if (randomInt < change) {
closeness.setText("Your answer is larger than the correct answer");
}
if (randomInt != change) {
status.setText("Wrong choice! Try again.");
status.setForeground(Color.red);
failedAttempts[0]++;
if (failedAttempts[0] == 3) {
int plus = randomInt + randomHint;
int minus = randomInt - randomHint2;
hints.setText("Hint: I see you are struggling, here is a low range to make it easier!");
hints2.setText("The lowered range is from " + plus + " to " + minus);
}
}
});
rules.setText("");
rulesText.setText("");
rulesText2.setText("");
frame.add(hints);
frame.add(hints2);
frame.add(label);
frame.add(check);
frame.add(closeness);
frame.add(text);
}
exit = new JButton("Exit");
exit.setBounds(350, 300, 100, 75);
exit.addActionListener(e -> {
int result = JOptionPane.showConfirmDialog(frame,"Are you sure want to exit?", "Exit",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if(result == JOptionPane.YES_OPTION){
System.exit(0);
}
});
frame.add(play);
frame.add(exit);
frame.add(rules);
frame.add(rulesText);
frame.add(rulesText2);
frame.setVisible(true);
}
public static void main(String[] args) {
NumberGame number = new NumberGame();
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
You're still thinking in console applications, Swing is designed to work with events...
The user pressed a button? An event
Some timer triggered something in the background? An event
User typed something? An event
So, with the above in mind, you cannot expect your code here:
play.addActionListener(e -> {
gameRunning = true;
});
while(gameRunning = true) {
...
}
To be executed in that order, because you have no control of when the user is going to press the button, it could be either in 2 seconds, or could be in 2 hours
For this to happen, you might need to move the while loop to a method, and when the user presses the play button, you need to change gameRunning = true and then call that other method, something like this:
public void runGame() {
while(gameRunning) {
// Your code here
}
}
play.addActionListener(e -> {
if (!gameRunning) { //This validation is needed otherwise if you press the button multiple times you'll have multiple loops running
gameRunning = true;
runGame();
}
});
This way, you don't start your game until the user presses the play button.
Notice how I just wrote while(gameRunning) without ==, as mentioned in the comments above, if you have gameRunning = true you're assigning it a value instead of comparing it, when using boolean variables you can simply write them like that, it reduces the possibility of typos like that one.
if(true) is the same as if (true == true)
if(!false) is the same as if (false == false)
if(false) is the same as if (true == false)
And as I mentioned in my previous answer avoid the use of null-layout and setBounds and why are you implementing ActionListener and never using it? It's empty, so just remove implements ActionListener
You can not change the value of a local variable in a lambda function. As I am sure the compiler is telling you, they need to be final or effectively final which means they are only assigned once.
The solution is to use a type that can hold your Boolean and change the value that it is holding instead.
AtomicBoolean gameRunning = new AtomicBoolean(false);
play.addActionListener(e -> {
gameRunning.set(true);
});
...
while(gameRunning.get()) {
}

Showing output on JFrame pop-up while in a loop

I'm a beginner programmer, and it's my first time trying out JFrames and stuff, so feel free to criticize any violations to good programming practices. I've tried many things but none have really worked so I'm stuck.
I'm trying to make 2 pop-up windows with JFrame, one which ask for button press and then opens another one which "simulates" labels (in this case just a string of text) moving systematically. I've put it in a loop and hoped it would update the text each time, simulating it moving on the window.
But the issue is it's just showing a blank screen for the duration of the loop, and only when it's complete it shows the text on the window. How can I fix it to print the text everytime on the window, not just at the end? I've put a 200 ms delay so I could spot the text moving but it's no use if it isn't even printing the text.
Here is my code:
public class PopUpWindow {
JButton button1, button2;
JLabel text1, text2;
JFrame window1, window2;
public PopUpWindow() {
this.window1 = new JFrame("Input");
this.window1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.window1.setLayout(null);
this.window2 = new JFrame("Simulation");
this.window2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.window2.setLayout(null);
}
public void createWindow1() {
this.button1 = new JButton("Start");
this.button2 = new JButton("Quit");
this.button1.setBounds(50, 50, 100, 30);
this.button2.setBounds(180, 50, 100, 30);
this.window1.add(button1);
this.window1.add(button2);
this.window1.setSize(350, 200);
this.window1.setVisible(true);
this.window1.setResizable(true);
this.window1.setLocationRelativeTo(null);
analyzeInput();
}
public void analyzeInput() {
this.button1.addActionListener((ActionEvent e) -> {
createWindow2();
});
this.button2.addActionListener((ActionEvent e) -> {
int question = JOptionPane.showConfirmDialog(this.window1, "Exit program?");
if (question == JOptionPane.YES_OPTION) {
this.window1.dispose();
}
});
}
public void createWindow2() {
this.button1 = new JButton("Button 1");
this.button2 = new JButton("Button 2");
this.text1 = new JLabel("x");
this.text2 = new JLabel("x");
int x = 80;
int y = 0;
for (int i = 0; i < 10; i++) {
this.button1.setBounds(50, 120, 100, 30);
this.button2.setBounds(180, 120, 100, 30);
this.text1.setBounds(x, y, 100, 100);
this.text2.setBounds(x, (y + 30), 100, 100);
this.window2.add(text1);
this.window2.add(text2);
this.window2.setSize(350, 250);
this.window2.setResizable(true);
this.window2.setVisible(true);
this.window2.setLocationRelativeTo(null);
x += 5;
y += 10;
try {
Thread.sleep(200);
} catch (InterruptedException ex) {
Logger.getLogger(PopUpWindow.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
EDIT:
well, let's ignore the for-loop for now. What I mainly wanted to know was why the JFrame window will not update or change despite me changing its content. For example, here is an edited version of createWindow2() -method, which does not have a for-loop and instead reacts to another button.
public void createWindow2() {
this.window2.setSize(500, 500);
this.window2.setVisible(true);
this.window2.setResizable(true);
this.window2.setLocationRelativeTo(null);
this.text1 = new JLabel("xfdfgdf");
this.text2 = new JLabel("xdfgdfgd");
this.button3 = new JButton("dfsadfas");
this.button3.setBounds(50, 50, 100, 30);
this.window2.add(this.button3);
this.button3.addActionListener((ActionEvent e) -> {
this.text1.setBounds(200, 200, 100, 100);
this.text2.setBounds(200, 230, 100, 100);
this.window2.add(text1);
this.window2.add(text2);
});
}
When I run the program, I only see a blank window, even though I press the button. Only when I rezise the window manually will the text appear in the correct coordinates. Is it supposed to work like that? Is there a way to make it update on every button press on its own? (I haven't done anything with Layouts or stuff so I don't know how that works.)

Swing gui not hiding/showing properly

I am writing this gui in java and it works great, except I recently discovered a bug. Currently I access each of my screens through file menus and use the below method to switch back and forth between the panels I am looking at. I have also included the method which one of the file menu actionlisteners executes. For the sake of brevity I have not included the others, just know that they use the same types of commands in a very similar order.
The problem is that sometimes when clicking between the screens, elements of the previous panel will be still visible on the new panel. This new panel will usually be missing most or all of its elements as well. Another (and probably related) issue I am experiencing is that when I run the code half or more of the time I see my initial screen but after that when I click to a new screen nothing shows up at all. It is very confusing because I don't change anything with the code or even recompile between runs and it behaves differently. This second problem has only been occurring since I moved the add methods for the panels to the setCurrentPanel for simplicity's sake.
private void setCurrentPanel(JPanel current) {
System.out.println(oldCurrent.getName() + " " + current.getName());
if (oldCurrent.getName().equals(current.getName())) {
} else {
buildingPanel.setVisible(false);
securityPanel.setVisible(false);
adminUsersPanel.setVisible(false);
adminBuildingPanel.setVisible(false);
adminServerPanel.setVisible(false);
changePasswordPanel.setVisible(false);
serverSettingsPanel.setVisible(false);
addBuildingPanel.setVisible(false);
addUser.setVisible(false);
for (BuildingItem item : buildingMenuItem) {
item.panel.setVisible(false);
}
add(current);
current.setVisible(true);
revalidate();
repaint();
oldCurrent = current;
refreshCount = refreshCount + 1;
System.out.println("Refresh " + refreshCount);
}
}
private void setupAdminServerPanel() {
getServerSettingsFromSQL();
serverSettingsPanel = new JPanel(new GridBagLayout());
serverSettingsPanel.setName("Server Settings Panel");
GridBagConstraints gbr = new GridBagConstraints();
SpinnerModel minPasswordModel = new SpinnerNumberModel(Integer.parseInt(settingMinPassword), 5, 20, 1);
SpinnerModel minUsernameModel = new SpinnerNumberModel(Integer.parseInt(settingMinUsername), 5, 20, 1);
final JSpinner minPasswordSpinner = new JSpinner(minPasswordModel);
final JSpinner minUsernameSpinner = new JSpinner(minUsernameModel);
JButton lockdownButton = new JButton("Lockdown");
lockdownButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
lockdownMode();
}
});
JButton ApplyButton = new JButton("Apply");
ApplyButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if (minPasswordSpinner.getValue() != Integer.parseInt(settingMinPassword) ||
(minUsernameSpinner.getValue() != Integer.parseInt(settingMinUsername))) {
writeSettingsToSQL((Integer) minPasswordSpinner.getValue(),
(Integer) minUsernameSpinner.getValue());
getServerSettingsFromSQL();
}
}
});
lockdownButton.setPreferredSize(new Dimension(50, 50));
minUsernameSpinner.setPreferredSize(new Dimension(150, 30));
minPasswordSpinner.setPreferredSize(new Dimension(150, 30));
gbr.gridy = 0;
gbr.gridx = 1;
gbr.gridwidth = 1;
gbr.ipady = 0;
gbr.insets = new Insets(10, 10, 10, 10);
serverSettingsPanel.add(lockdownButton, gbr);
gbr.gridy = 1;
gbr.gridx = 0;
serverSettingsPanel.add(new JLabel("Minimum Username Length"), gbr);
gbr.gridy = 2;
gbr.gridx = 0;
serverSettingsPanel.add(new JLabel("Minimum Password Length"), gbr);
gbr.gridy = 1;
gbr.gridx = 1;
gbr.gridwidth = 2;
serverSettingsPanel.add(minUsernameSpinner, gbr);
gbr.gridy = 2;
serverSettingsPanel.add(minPasswordSpinner, gbr);
gbr.gridy = 3;
gbr.gridx = 1;
gbr.gridwidth = 1;
serverSettingsPanel.add(ApplyButton, gbr);
setCurrentPanel(serverSettingsPanel);
}
If you need to see more of the code let me know. I really would appreciate any help I can get! Thanks
I am not allowed to comment, so maybe it is not a full answer:
You revalidate and repaint the panel, do you do it to the frame or panel, in which it is displayed?
As already suggested, Card Layout is a better way.

Java NPE with .split

I'm fairly new with Java, (and this site) so I'm not sure what to do with this "issue"...
I'm not sure whether to put my entire code in this or not...So I'll just put what I think is causing the issue. The program compiles perfectly, except when I try to run it. That's when I get a Null Pointer Exception at line 96. I have no idea why this is happening.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class LicensePlateGeneratorTemplate extends JFrame implements ActionListener{
private JTextArea txtOutput;
private JTextField txtNumPlates;
private JButton btnDisplay;
private JLabel lblTitle, lblInstruction;
private PrintWriter output;
private String letters, numbers, fileName;
private int randomLetter, randomNumber, numPlates;
private String [] a, b ;
private String [] lttrArray, nmbrArray;
public static void main(String[] args) throws IOException{
new LicensePlateGeneratorTemplate();
}
public LicensePlateGeneratorTemplate() throws IOException{
//label thast contains number of licence plates generated
txtNumPlates = new JTextField();
txtNumPlates.setBounds(320, 60, 28, 28);
lblInstruction = new JLabel("How many license plates would you like to generate?");
lblInstruction.setBounds(15, 60, 300, 28);
//A random number generator in the action performed method should allow you to select a random letter from the letters String
//then a random number from the numbers String
String letters = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Z";
String numbers = "1,2,3,4,5,6,7,8,9,0";
lttrArray = letters.split (",");
nmbrArray = numbers.split (",");
System.out.println(lttrArray[20] + lttrArray [10]);
System.out.println(nmbrArray[3]+ nmbrArray [5]);
fileName = "licensePlates.txt";
output = new PrintWriter(new FileWriter(fileName));
lblTitle = new JLabel();
lblTitle.setFont(new Font("Britannic Bold", Font.BOLD, 28));
lblTitle.setText("License Plate Generator");
lblTitle.setBounds(30, 10, 400, 50);
JPanel panel = new JPanel();
panel.setLayout(null);
//JTextArea
txtOutput = new JTextArea();
txtOutput.setBounds(60, 150, 275, 196);
txtOutput.setEditable(true);
//generate button properties
btnDisplay = new JButton();
btnDisplay.setText("Generate");
btnDisplay.setBounds(150, 100, 100, 40);
btnDisplay.setFocusable(true);
btnDisplay.addActionListener(this);
//add components to the panel
panel.add(btnDisplay);
panel.add(txtOutput);
panel.add(lblTitle);
panel.add(lblInstruction);
panel.add(txtNumPlates);
//frame properties
setContentPane(panel);
setSize(400, 400);
setTitle("License Plate Generator");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
}
public void actionPerformed (ActionEvent e)
{
if (e.getSource() == btnDisplay)
{
//change number user inputs into a int value
int userNum = Integer.parseInt(txtNumPlates.getText ());
for (int k = 0; k <= userNum; k ++)
{//number of licence places that are being made
for (int i = 0; i < 4; i ++)//loop for letters produced
{
int randLtr = 0 + (int)(Math.random() * ((24 - 0) + 1));
a [i] = lttrArray [randLtr];
output.println (a[i]);
txtOutput.insert(a[i] + "\n", 0);
}
for (int j = 0; j < 3; j++)//loop for number produced
{
int randNum = 0 + (int)(Math.random() * ((9 - 0) + 1));
b [j] = nmbrArray [randNum];
output.println (b[j]);
txtOutput.insert(b[j] + "\n", 0);
}
output.close();//closes fileWriter
}//end of userNum loop
}//end of e.getsource
}
}
Edit: Added full code.
Since lttrArray is clearly non-null (unless you're assigning it as lttrArray = null somewhere in the snipped code), I would guess that a is null.

Categories

Resources