So I'm making a Java Calculator and walking into some errors upon clicking the function buttons (it compiles perfectly fine though).
The error on the 1st line in my CMD was a NumberFormat Exception. After some searching I figured out that somewhere in my code I was trying to get a double out of an empty string (basically what I'm trying to do is parse a double from the label text). I'm guessing it's this part:
// if statement that puts the labels text into the first or second number
if(firstNumber)
{
number1 = Double.parseDouble(label.getText().trim());
} else {
number2 = Double.parseDouble(label.getText().trim());
}
Basically the problems are when i push the / * + or - button i get a NumberFormatExeption: For input string "/" etc.
I can't quite figure out how i have to fix this error (I'm still (somewhat) a beginner in Java).
Further down the line of errors (there were quite alot) were a whole lot of errors I didn't understand such as EventDispatchThread, EventQueue and many others. I couldn't find an explanation on my level of experience either so I'm asking for help here.
The numeric buttons all work fine.
At run: [http://gyazo.com/71cb4dde449ccf7ece44017388a71a0f]
Putting in numbers: [http://gyazo.com/5c7ab6c54ac6da180845c66866d66f8f]
All other buttons give errors in my CMD.
Here's my code (the spacing might be messed up in some parts):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
// import for Nimbus look
import javax.swing.UIManager.*;
public class Calculator extends JFrame implements ActionListener
{
private JPanel bottom = new JPanel(); private JPanel top = new JPanel();
private JLabel label = new JLabel(" ");
private JButton[] buttons = new JButton[16];
// booleans for calculator functions
boolean add = false, substract = false, devide = false, multiply = false, firstNumber = true;
// numbers that will be calculated
double number1, number2;
public Calculator()
{
setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
// bottom panel
bottom.setPreferredSize(new Dimension(100,100));
bottom.setLayout(new BorderLayout());
//add bottom panel to frame
add(bottom);
// top panel
top.setPreferredSize(new Dimension(300,400));
top.setLayout(new GridLayout(4,4,3,3));
top.setBackground(Color.BLACK);
//dont add top panel to frame: you want top to be on bottom
// add top panel to bottom panel
bottom.add(top);
// label
label.setFont(new Font("Courier", Font.PLAIN, 20));
label.setBackground(Color.BLACK);
label.setForeground(Color.WHITE);
label.setHorizontalAlignment(SwingConstants.RIGHT); // text is right-aligned
label.setOpaque(true);
// add the label to the bottom panel
bottom.add(label, BorderLayout.NORTH);
// creating buttons
for(int i = 0; i < buttons.length; i++)
{
buttons[i] = new JButton("789/456*123+c0=-".substring(i, i+1));
buttons[i].addActionListener(this);
// add them to the top panel
top.add(buttons[i]);
}
// Nimbus look
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// If Nimbus is not available, you can set the GUI to another look and feel.
//set to default somehow o.o
}
// frame setters
setTitle("Calculator");
setSize(400,400);
setVisible(true);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void Clear()
{
label.setText(" ");
}
#Override
public void actionPerformed(ActionEvent e)
{
//if's for all function buttons
if(e.getSource() == buttons[3])
{
// devide
devide = true;
substract = false;
add = false;
multiply = false;
firstNumber = false;
Clear();
label.setText("/");
}
if(e.getSource() == buttons[7])
{
// multiply
multiply = true;
substract = false;
devide = false;
add = false;
firstNumber = false;
Clear();
label.setText("*");
}
if(e.getSource() == buttons[11])
{
// add
add = true;
substract = false;
devide = false;
multiply = false;
firstNumber = false;
Clear();
label.setText("+");
}
if(e.getSource() == buttons[12])
{
// clear
label.setText("0");
number1 = 0.00;
number2 = 0.00;
add = false;
substract = false;
devide = false;
multiply = false;
firstNumber = true;
Clear();
}
if(e.getSource() == buttons[15])
{
// substract
substract = true;
add = false;
devide = false;
multiply = false;
firstNumber = false;
Clear();
label.setText("-");
}
// for loops that add the numbers on the buttons to the label
for(int i = 0; i < 3; i++)
{
if(e.getSource() == buttons[i])
{
if(label.getText() == "0")
{
label.setText("");
label.setText(label.getText() + buttons[i].getText());
} else {
label.setText(label.getText() + buttons[i].getText());
}
}
}
for(int i = 4; i < 7; i++)
{
if(e.getSource() == buttons[i])
{
if(label.getText() == "0")
{
label.setText("");
label.setText(label.getText() + buttons[i].getText());
} else {
label.setText(label.getText() + buttons[i].getText());
}
}
}
for(int i = 8; i < 11; i++)
{
if(e.getSource() == buttons[i])
{
if(label.getText() == "0")
{
label.setText("");
label.setText(label.getText() + buttons[i].getText());
} else {
label.setText(label.getText() + buttons[i].getText());
}
}
}
for(int i = 13; i < 14; i++)
{
if(e.getSource() == buttons[i])
{
if(label.getText() == "0")
{
label.setText("");
label.setText(label.getText() + buttons[i].getText());
} else {
label.setText(label.getText() + buttons[i].getText());
}
}
}
// if statement that puts the labels text into the first or second number
if(firstNumber)
{
number1 = Double.parseDouble(label.getText().trim());
} else {
number2 = Double.parseDouble(label.getText().trim());
}
// calculation
if(e.getSource() == buttons[14])
{
// calculate
if(devide){number1 = ((double)(number1) / (double)(number2)); }
if(multiply){number1 = ((double)(number1) * (double)(number2)); }
if(add){number1 = ((double)(number1) + (double)(number2)); }
if(substract){number1 = ((double)(number1) - (double)(number2)); }
label.setText(Double.toString(number1));
}
}
public static void main(String[] args)
{
new Calculator();
}
}
Lastly, the calculations made by the calculator are incorrect. I also can't wrap my head around what's causing that. Please bear in mind that I'm a beginner at Java and this is my first question on stackoverflow. Thanks in advance for helping me, whoever will :)
UPDATE: i fixed the errors by putting my code as follows:
if(e.getSource() == buttons[15])
{
// substract
substract = true;
add = false;
devide = false;
multiply = false;
firstNumber = false;
isNumberKey = false;
if(isNumberKey)
{
if(firstNumber)
{
label.setText(label.getText().replace("/",""));
label.setText(label.getText().replace("*",""));
label.setText(label.getText().replace("+",""));
label.setText(label.getText().replace("-",""));
number1 = Double.parseDouble(label.getText().trim());
} else {
label.setText(label.getText().replace("/",""));
label.setText(label.getText().replace("*",""));
label.setText(label.getText().replace("+",""));
label.setText(label.getText().replace("-",""));
number2 = Double.parseDouble(label.getText().trim());
}
}
Clear();
label.setText("-");
}
All i need to do now is fix the calculations...
Thanks for the help everyone!
Cannot delve totaly into your logic there, but here's some hints:
First, you don't have to guess where the error is. In case of uncaught exception like here, thread that produced it will print it's stack trace to console. It looks like this:
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "/"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1222)
at java.lang.Double.parseDouble(Double.java:510)
at mypackage.Calculator.actionPerformed(Calculator.java:229)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6297)
From here you see that exception happened in thread named AWT-EventQueue-0, which is swing's standard event dispatching thread (all GUI applications handles events in single thread). Another thing you search in stack trace is to find what line in your code thrown it. Here it's the line:
at mypackage.Calculator.actionPerformed(Calculator.java:229)
In source, it is line:
number2 = Double.parseDouble(label.getText().trim());
, so you guessed right. What you can do is add another boolean there which will be set only if number button is hit, and then change that part of code to something like:
if( isNumber){
if(firstNumber)
{
number1 = Double.parseDouble(label.getText().trim());
} else {
number2 = Double.parseDouble(label.getText().trim());
}
}
Apart from that, instead of using multiple boolean flags for operation, use Java enum type
enum Operation {devide, substract, add, multiply};
your code will be more readable and "java" styled.
Good starting point, just go ahead!
Disclaimer: I'm on my phone so it's hard to parse your code; with that being said, I believe your number format exception deals with what is stored in the label text.
From the looks of it if you hit an operator button (like multiply), the labelText will be "*", then if you hit number button (like 5), the labelText will be "*5". Finally, if you hit the enter button now to go calculate the answer, Double.parseDouble(label.getText().trim()), will be ran which will throw the NumberFormatException. Using the operation flags, it looks like you don't even need to store the operator (unless you're trying to display the operator to the user); in that case you need to strip the operator from the string before trying the parse the double.
label.setText(label.getText().replace("/",""));
label.setText(label.getText().replace("*",""));
label.setText(label.getText().replace("+",""));
label.setText(label.getText().replace("-",""));
As for the other exceptions, in eclipse you can set a breakpoint to halt the program when a specific exception occurs. This will help you debug your code further.
more info on that here
Related
So, I'm trying to program a Game of Life simulation (Conway), and I want to show it in a JFrame.
For this purpose, I've created a JPanel, and it works perfectly, until I try to actually show a new generation. With prints, I've figured out, that the list is actually correct inside the newGeneration() method, but when paint(Graphics g) gets called (aka, when I try to repaint the JFrame), the list isn't updating.
I'm sure I've missed something obvious, and I'm not well versed in Java, but it's just getting so annoying. I'd really appreciate your help.
Here's my code;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Main {
public static void main(String[] args) {
new GameOfLife();
}
}
class GameOfLife {
// Initialising all class wide variables; sorted by type
JFrame frame = new JFrame("Game of Life");
JPanel panel;
Scanner gameSize = new Scanner(System.in);
String dimensions;
String splitHorizontal;
String splitVertical;
String confirmation;
Boolean accepted = false;
Integer split;
Integer horizontal;
Integer vertical;
Integer livingNeighbours;
int[][] cells;
int[][] newCells;
public GameOfLife() {
// Prompt for game Size
System.out.println("Please enter your game size in the following format; 'Horizontal,Vertical'");
// Run until viable game Size has been chosen
while (!accepted) {
dimensions = gameSize.nextLine();
// Check for correct format
if (dimensions.contains(",")) {
split = dimensions.indexOf(",");
splitHorizontal = dimensions.substring(0, split);
splitVertical = dimensions.substring(split + 1);
// Check for validity of inputs
if (splitHorizontal.matches("[0-9]+") && splitVertical.matches("[0-9]+")) {
horizontal = Integer.parseInt(dimensions.substring(0, split));
vertical = Integer.parseInt(dimensions.substring(split + 1));
// Check for game Size
if (horizontal > 1000 || vertical > 1000) {
System.out.println("A game of this Size may take too long to load.");
} else {
// Confirmation Prompt
System.out.println("Your game will contain " + horizontal + " columns, and " + vertical + " rows, please confirm (Y/N)");
confirmation = gameSize.nextLine();
// Check for confirmation, anything invalid is ignored
if (confirmation.matches("Y")) {
accepted = true;
System.out.println("Thank you for your confirmation. Please select live cells. Once your happy with your game, press Spacebar to start the Simulation.");
// Setting parameters depending on Size
frame.setSize(horizontal * 25 + 17, vertical * 25 + 40);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
}
}
// Prompt asking for new dimensions in case of invalid dimensions or non confirmation
if (!accepted) {
System.out.println("Please enter different dimensions.");
}
}
// Creating list of cells
cells = new int[horizontal][vertical];
// Showing the empty panel for selection of live cells
panel = new PaintCells(horizontal, vertical, cells);
frame.add(panel);
// Select live cells
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] == 1) {
cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] = 0;
} else {
cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] = 1;
}
frame.repaint();
}
});
// Simulation start
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == ' ') {
newGeneration();
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
});
}
// Generating new generations
void newGeneration() {
newCells = new int[horizontal][vertical];
// Pause inbetween generations
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* Way of Life Rules:
* Living cells with 2 or 3 living neighbours live on to the next generation.
* Dead cells with exactly 3 living neighbours become living cells in the next generation.
* Every other living cell dies.
*/
// iterate through every cell
for (int l = 0; l < vertical; l++) {
for (int k = 0; k < horizontal; k++) {
livingNeighbours = 0;
// check amount of neighbours
if (k - 1 > -1) {
if (l - 1 > -1) {
if (cells[k - 1][l - 1] == 1) {
livingNeighbours++;
}
}
if (l + 1 < vertical) {
if (cells[k - 1][l + 1] == 1) {
livingNeighbours++;
}
}
if (cells[k - 1][l] == 1) {
livingNeighbours++;
}
}
if (k + 1 < horizontal) {
if (l - 1 >= 0) {
if (cells[k + 1][l - 1] == 1) {
livingNeighbours++;
}
}
if (l + 1 < vertical) {
if (cells[k + 1][l + 1] == 1) {
livingNeighbours++;
}
}
if (cells[k + 1][l] == 1) {
livingNeighbours++;
}
}
if (l - 1 >= 0) {
if (cells[k][l - 1] == 1) {
livingNeighbours++;
}
}
if (l + 1 < vertical) {
if (cells[k][l + 1] == 1) {
livingNeighbours++;
}
}
// change cell value depending on amount of neighbours
if (cells[k][l] == 1) {
if (livingNeighbours < 2 || livingNeighbours > 3) {
newCells[k][l] = 0;
} else {
newCells[k][l] = 1;
}
} else {
if (livingNeighbours == 3) {
newCells[k][l] = 1;
}
}
}
}
cells = newCells;
frame.validate();
frame.paint(frame.getGraphics());
newGeneration();
}
}
// Our canvas
class PaintCells extends JPanel {
private Integer horizontal;
private Integer vertical;
private int[][] newOriginalCells;
// Get our X and Y from the original prompts
public PaintCells(Integer originalHorizontal, Integer originalVertical, int[][] originalCells) {
this.horizontal = originalHorizontal;
this.vertical = originalVertical;
this.newOriginalCells = originalCells;
}
#Override
public void paint(Graphics g) {
for (int i = 0; i < vertical; i++) {
for (int j = 0; j < horizontal; j++) {
// Check cell value
if (newOriginalCells[j][i] == 1) {
g.setColor(Color.black);
} else {
g.setColor(Color.white);
}
// paint according to value
g.fillRect(j * 25, i * 25, 25, 25);
if (newOriginalCells[j][i] == 1) {
g.setColor(Color.white);
} else {
g.setColor(Color.black);
} // maybe change style?
g.drawRect(j * 25, i * 25, 25, 25);
}
}
}
}
I'm guessing, the problem is somewhere in newGeneration(), but other than that, I really have no idea anymore.
You have a common problem which I had myself a few months ago.
Java Swing GUI system works in thread called Event Dispatch Thread (EDT). This thread handle events like mouse clicks, typing etc. and paint the components to the screen. You should use this thread not as your main thread, but as sub-thread which working only once a certain time/when event happens, and not let him run continuously. In your code, since the user choose the cell to live, this thread run non-stop (because you started the program inside a listener, which is part of the EDT), and your GUI stuck, because it's updating only at the end of the thread.
You can solve this by using javax.swing.Timer. Timer is an object that allows you do tasks once a while, and it is perfect to this problem.
Use code like this:
ActionListener actionListaner = new ActionListener(){
public void actionPerformed(ActionEvent e){
//Put here you ne genration repeating code
}
};
int delay = 1000;//You delay between generations in millis
Timer timer = new timer(delay, actionListener);
The code in the actionPerformed method will repeat every second (or any other time you want it to repeat), and every operation of the timer will recall EDT instead of let it run non-stop.
I created a dialog box and have the user enter 5 colors in it from memory. That all completely works, there's just a slight aesthetic problem. Upon entering all 5 colors correctly, or getting one incorrect, it's suppose to wipe the contents within the dialog box and print a message "Sorry! Incorrect color" or "Congratulations". It prints the message, but the JTextField can still be seen somewhat behind the message (A left over portion/clipping).
I've tried using the hide() and remove() methods but they didn't seem to work (Or I'm using them incorrectly), I tried re-making a dialog box upon either but I couldn't seem to solve the issue still. What am I doing wrong/how can I make the JTextField disappear upon completion? Thank you in advance for any help!
Here's the portion where if the user enters a color incorrectly or gets them all correct (txtName is the JTextField):
if(count == 6)//User either finished or entered a color incorrectly
{
//Entered color incorrectly
if(incorrect == true)
{
txtName.setEnabled(false); //Doesn't work
homeScreen.remove(txtName); //Doesn't work
labelName.setText("Incorrect! Sorry - Wrong color.");
//txtName.removeActionListener(new MyButtonListener());
}
else//Correctly finished the game.
{
labelName.setText("Congratulations - your memory skills are perfect!");
//txtName.removeActionListener(new MyButtonListener());
homeScreen.remove(txtName);//Doesn't work
}
}
Here's my entire program (I can't get it format properly in the post):
package memorygame;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.FlowLayout;
public class MemoryGame
{
private JFrame homeScreen;
private JLabel labelName;
private JTextField txtName;
private JLabel correct;
Vector<String> name = new Vector();
private int count = 1;
private MyButtonListener listen1 = new MyButtonListener();
//Constructor - Method to be called when MemoryGame object called
public void MemoryGame ()
{
homeScreen = new JFrame();
homeScreen.setSize(400,200);
homeScreen.setTitle("Memory Game");
homeScreen.setDefaultCloseOperation(homeScreen.EXIT_ON_CLOSE);
homeScreen.setLayout(new FlowLayout());
labelName = new JLabel();
txtName = new JTextField(10);
createContents();
homeScreen.setVisible(true);
}//End Constructor
//Create components and add them to the window/dialog box
private void createContents()
{
labelName.setText("Enter the color " + count + ":");
System.out.println("The current count is: " + count);
homeScreen.add(labelName);
homeScreen.add(txtName);
txtName.addActionListener(new MyButtonListener());//Allows you to press enter to invoke action
}
//Upon user hitting enter
private class MyButtonListener implements ActionListener
{
public void actionPerformed (ActionEvent e)//When event occurs
{
Scanner in = new Scanner (System.in);//For program input
String answer = "";
//Make memColor an array for randomized colors
/*
Random r = new Random();
String[] memColors = new String[5];
String[] colors = {"red", "green", "blue", "yellow", "brown", "purple"};
for(int i =0; i < memColors.length; i++)
{
memColors[i] = colors[r.nextInt(6)];
}
*/
String memColor1 = "red";
String memColor2 = "black";
String memColor3 = "yellow";
String memColor4 = "green";
String memColor5 = "blue";
boolean incorrect = false;
//If answered incorrectly set count to 5(it'll be 6)
//And have a boolean for if count== 6 for congrats and failure
if(e.getSource() == txtName)
{
answer = txtName.getText();
System.out.println(answer);
}
else
{}
//Check if user entered Correct color, 1= Red, 2= Black, etc.
if(count == 1)
{
if(answer.equalsIgnoreCase(memColor1))
{
txtName.setText("");
}
else
{//Needs to be a custom message box
count = 5;
incorrect = true;
}
}
else if(count == 2)
{
if(answer.equalsIgnoreCase(memColor2))
{
txtName.setText("");
}
else
{
count = 5;
incorrect = true;
}
}
else if(count == 3)
{
if(answer.equalsIgnoreCase(memColor3))
{
txtName.setText("");
}
else
{
count = 5;
incorrect = true;
}
}
else if(count == 4)
{
if(answer.equalsIgnoreCase(memColor4))
{
txtName.setText("");
}
else
{
count = 5;
incorrect = true;
}
}
else if(count == 5)
{
if(answer.equalsIgnoreCase(memColor5))
{
txtName.setText("");
}
else
{
count = 5;
incorrect = true;
}
}
else
{
JOptionPane.showMessageDialog(null, "Something went wrong!");
}
count += 1;
//User has completed the game or entered a color incorrectly
if(count == 6)
{
if(incorrect == true) //Incorrect color
{
txtName.setEnabled(false);
homeScreen.remove(txtName);
labelName.setText("Incorrect! Sorry - Wrong color.");
//txtName.removeActionListener(new MyButtonListener());
}
else //Completed the game correctly
{
labelName.setText("Congratulations - your memory skills are perfect!");
//txtName.removeActionListener(new MyButtonListener());
homeScreen.remove(txtName);
}
}
else
{
labelName.setText("Enter the color " + count + ":");
}
}//End Listener
}//End Button class
public static void main(String[] args) {
//Show message box
//Randomize colors
JOptionPane.showMessageDialog(null, "How good is your memory?\nTry to memorize this color sequence:\n\n red black yellow green blue");
MemoryGame mem = new MemoryGame();
mem.MemoryGame();
}//End Main
}// End Class
Use txtName.setVisible(false); instead of homeScreen.remove(txtName);
Basically, if you want to call remove, you will need to revalidate and repaint container...
You'll also want to ensure that your UI is create within the context of the Event Dispatching Thread, see Initial Threads for more details
Change the code
homeScreen.remove(txtName);
to
homeScreen.remove(txtName);
homeScreen.revalidate();
homeScreen.repaint();
The reason why remove() does not imply revalidate() + repaint() is that remove() is not atomic. The caller might want to perform multiple updates, a sequence of several add() and remove() calls. revalidate() basically "completes" your "UI update transaction", repaint() "pushes it to the screen".
As a side note, your code will be easier to understand and maintain, if you perform a small tiny improvements on variable names. What's homeScreen? And why is it called labelName - what name? And what's txtName - the name of what text? count of what, icecreams?
I suggest the following improvements:
incorrect -> isIncorrect (also change if (incorrect == true) to if (isIncorrect)
homeScreen -> mainFrame or just frame (as you only have one frame)
labelName -> infoLabel or just label (as you only have one label - and remove JLabel correct, it's unused)
txtName -> answerTextField
count -> answerCount
Remove variable listen1, it's not used.
Plus, if you look at the code that does if (count == 1) and the following four if clauses, they are all identical except for the number. A perfect situation for an array. You can convert the variables memColor* to an array String[] memColor. Or maybe that's what the Vector was for. You might instead want to use ArrayList, nobody uses Vector these days in such situations.
I have a button. If I click this button, a popup appears. The popup asking me to write a word. if I write a word 6 letter, 6 jlabels appear, but if I enter another word shorter, the JLabels do not disappear
I want my JLabels may decrease according to a shorter word, but i don't know :(
thx for your great help !
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//BUTTON 1 WORD
Controller c = new Controller();
try {
final JFrame popup = new JFrame();
//display popup
word = JOptionPane.showInputDialog(popup, "Enter one word", null);
//control the length of the word
c.controleW(word);
//display jlabel lenght of word
keyNumber.setText(String.valueOf(word.length()));
//JLabels displays depending on the word length
int pixels = 50;
for (int i = 0; i < word.length(); i++) {
label = new JLabel("_");
label.setBounds(pixels, 200, 30, 30);
add(label);
label.repaint();
pixels += 20;
}
} catch (Exception e) {
System.out.println(e);
}
}
And my class to control the length of the word
public String controleW(String word) {
boolean flag = false;
final JFrame popup = new JFrame();
while (flag == false) {
if (word.length() <= 3) {
word = JOptionPane.showInputDialog(popup, "Enter one word", null);
} else {
flag = true;
}
};
return null;
}
You are always adding labels in your method, never removing any, thus running the code twice will indeed add labels twice. To fix it, you can simply add a removeAll(); in jButton1ActionPerformed before you add any labels. This makes sure that any previously added components will be removed.
So I have a JFrame in Netbeans that holds 20 labels of math equations.
mathLabel1 is "2 + 2"
mathLabel2 is "4 * 4"
etc...
and if mathLabel1 is shown and the user guesses the right answer (4) then I want to setVisible(false) and remove that element from my array, so it doesn't come up as a question again.
Basically, no repeats.
Here is a short version of my code:
//declare variables
String strUserAnswer;
int i;
Random r = new Random();
int randvalue = r.nextInt(19);
JLabel[] math = {mathLabel1, mathLabel2, mathLabel3, mathLabel4, mathLabel5, mathLabel6, mathLabel7, mathLabel8, mathLabel9, mathLabel10,
mathLabel11, mathLabel12, mathLabel13, mathLabel14, mathLabel15, mathLabel16, mathLabel17, mathLabel18, mathLabel19, mathLabel20};
JLabel test;
//method that chooses random math equation
public void random(JLabel test) {
r = new Random();
randvalue = r.nextInt(19);
test = math[randvalue];
if (test == math[0]) {
mathLabel1.setVisible(true);
}
else if (test == math[1]){
mathLabel2.setVisible (true);
}
else if (test == math[2]){
mathLabel3.setVisible (true);
}
else if (test == math[3]){
mathLabel4.setVisible (true);
}
else if (test == math[4]){
mathLabel5.setVisible (true);
}
else if (test == math[5]){
mathLabel6.setVisible (true);
}
else if (test == math[6]){
mathLabel7.setVisible (true);
}
else if (test == math[7]){
mathLabel8.setVisible (true);
}
else if (test == math[8]){
mathLabel9.setVisible (true);
}
else if (test == math[9]){
mathLabel10.setVisible (true);
}
else if (test == math[10]){
mathLabel11.setVisible (true);
}
else if (test == math[11]){
mathLabel12.setVisible (true);
}
else if (test == math[12]){
mathLabel13.setVisible (true);
}
else if (test == math[13]){
mathLabel14.setVisible (true);
}
else if (test == math[14]){
mathLabel15.setVisible (true);
}
else if (test == math[15]){
mathLabel16.setVisible (true);
}
else if (test == math[16]){
mathLabel17.setVisible (true);
}
else if (test == math[17]){
mathLabel18.setVisible (true);
}
else if (test == math[18]){
mathLabel19.setVisible (true);
}
else if (test == math[19]){
mathLabel20.setVisible (true);
}
}
private void guessButtonActionPerformed(java.awt.event.ActionEvent evt) {
// User clicks guess to enter answer, if correct part of puzzle appears
strUserAnswer = answerText.getText();
test = math[randvalue];
//if the math equation chosen is 2+2...
if (test == math[0]) {
//show math equation
mathLabel1.setVisible(true);
//if answer is right...
if (strUserAnswer.equals("4")) {
JOptionPane.showMessageDialog(null, "Yay!! That is right!");
//show puzzle piece, hide equation, and choose a new one
label1.setVisible(true);
mathLabel1.setVisible(false);
//test.remove(math[0]);
test = math[randvalue];
answerText.setText(null);
random(test);
//if answer is wrong...
} else {
JOptionPane.showMessageDialog(null, " Sorry, try again!");
answerText.setRequestFocusEnabled(true);
}
}
and that's repeated for math[1], math[2], math[3], etc...
So how would I do this? I tried the remove() method but that was a shot in the dark...
ok, so this might make your day or break your heart, but you are doing way more than you need to with your random() method. first off, it doesn't seem like you need to take in a parameter
because it looks like you are manually changing the value before you ever use it. also, because each value in the array is in fact a JLabel, you can just say math[randValue].setVisible(true) instead of going through the whole if statement thing. and to solve your problem of removing stuff, there is a quick and dirty way you can do it that i will show you, but you are better off using an ArrayList instead of an Array.
public void random() {
Random r = new Random();
randValue = r.nextInt(math.length); //make sure the index is always within the array
JLabel[] temp = new JLabel[math.length - 1]; //this will do the trick
math[randValue].setVisible(true);
for (int i = 0; i < randvalue; i++) {
temp[i] = math[i]; //fill the new array up to the chosen label
}
for (int i = randValue; i < temp.length; i++) {
temp[i] = math[i + 1]; //fill the rest, omitting the chosen label
}
math = new JLabel[temp.length]; //math is now shorter
math = temp; //put everything back in the original array
}
this should work as a solution using arrays.
hope it helps.
If your data structure will constantly be changing, try using a List instead of an Array:
List<JLabel> labels = new ArrayList<JLabel>();
int numLabels = 20;
for (int i = 0; i < numLabels; i++) {
labels.add(new JLabel(i + " " + i));
}
From there you could always call:
labels.get(4).setVisible(false);
or
labels.remove(4);
And then revalidate your JPanel.
EDIT 2:
I may have misunderstood your question - it seems you want to remove a number and never create a label for it again. This is the correct way to do it:
int numIntegers = 20;
Set<Integer> possibleNumbers = new HashSet<Integer>();
for (int i = 0; i < numIntegers; i++) {
possibleNumbers.add(i);
}
When you want to remove an item, use:
possibleNumbers.remove(14);
Then when you want to present this data, you can use:
panel.clear();
for (Integer number : possibleNumbers) {
panel.add(new JLabel(number + " " + number));
}
(Please note I was incorrect calling JLabels data - they are part of the presentation.)
I need to make the following exceptions: NoSuchRowException if the row is not between 1 and 3, IllegalSticksException if the number of sticks taken is not between 1 and 3, and NotEnoughSticksException if the number of sticks taken is between 1 and 3, but more than the number of sticks remaining in that row. My issue is I really don't understand the syntax. If someone could help me get started with one exception, I think I can figure the others out.
So far I have the main class:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package nimapp;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
*
* #author jrsullins
*/
public class NimApp extends JFrame implements ActionListener {
private static final int ROWS = 3;
private JTextField[] gameFields; // Where sticks for each row shown
private JTextField rowField; // Where player enters row to select
private JTextField sticksField; // Where player enters sticks to take
private JButton playButton; // Pressed to take sticks
private JButton AIButton; // Pressed to make AI's move
private NimGame nim;
public NimApp() {
// Build the fields for the game play
rowField = new JTextField(5);
sticksField = new JTextField(5);
playButton = new JButton("PLAYER");
AIButton = new JButton("COMPUTER");
playButton.addActionListener(this);
AIButton.addActionListener(this);
AIButton.setEnabled(false);
// Create the layout
JPanel mainPanel = new JPanel(new BorderLayout());
getContentPane().add(mainPanel);
JPanel sticksPanel = new JPanel(new GridLayout(3, 1));
mainPanel.add(sticksPanel, BorderLayout.EAST);
JPanel playPanel = new JPanel(new GridLayout(3, 2));
mainPanel.add(playPanel, BorderLayout.CENTER);
// Add the fields to the play panel
playPanel.add(new JLabel("Row: ", JLabel.RIGHT));
playPanel.add(rowField);
playPanel.add(new JLabel("Sticks: ", JLabel.RIGHT));
playPanel.add(sticksField);
playPanel.add(playButton);
playPanel.add(AIButton);
// Build the array of textfields to display the sticks
gameFields = new JTextField[ROWS];
for (int i = 0; i < ROWS; i++) {
gameFields[i] = new JTextField(10);
gameFields[i].setEditable(false);
sticksPanel.add(gameFields[i]);
}
setSize(350, 150);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
nim = new NimGame(new int[]{3, 5, 7});
draw();
}
// Utility function to redraw game
private void draw() {
for (int row = 0; row < ROWS; row++) {
String sticks = "";
for (int j = 0; j < nim.getRow(row); j++) {
sticks += "| ";
}
gameFields[row].setText(sticks);
}
rowField.setText("");
sticksField.setText("");
}
public void actionPerformed(ActionEvent e) {
// Player move
if (e.getSource() == playButton) {
// Get the row and number of sticks to take
int row = Integer.parseInt(rowField.getText())-1;
int sticks = Integer.parseInt(sticksField.getText());
// Play that move
nim.play(row, sticks);
// Redisplay the board and enable the AI button
draw();
playButton.setEnabled(false);
AIButton.setEnabled(true);
// Determine whether the game is over
if (nim.isOver()) {
JOptionPane.showMessageDialog(null, "You win!");
playButton.setEnabled(false);
}
}
// Computer move
if (e.getSource() == AIButton) {
// Determine computer move
nim.AIMove();
// Redraw board
draw();
AIButton.setEnabled(false);
playButton.setEnabled(true);
// Is the game over?
if (nim.isOver()) {
JOptionPane.showMessageDialog(null, "You win!");
playButton.setEnabled(false);
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
NimApp a = new NimApp();
}
}
The support class:
package nimapp;
import java.util.Random;
import javax.swing.JOptionPane;
import java.io.*;
import java.lang.*;
public class NimGame {
int x = 1;
int[] Sticks; //creating an array of sticks
int totalSticks = 0;
public NimGame(int[] initialSticks){
Sticks = initialSticks;}
public int getRow(int r){
return Sticks[r];}
public void play(int r, int s) throws IllegalSticksException {
try {
Sticks[r]=Sticks[r]-s;
if(s < 0 || s > 3)
throw new IllegalSticksException();
} catch (IllegalSticksException ex){
JOptionPane.showMessageDialog(null, "Not a valid row!");
} catch (IndexOutOfBoundsException e){
JOptionPane.showMessageDialog(null, "Too Many Sticks!");
}
}
public boolean isOver(){
int theTotal = 0;
for (int i = 0; i< Sticks.length; i++){
theTotal = Sticks[i];
System.out.println(Sticks[i]);
System.out.println(theTotal);
}
totalSticks = theTotal;
if (totalSticks <= 0){
return true;
}
else return false;
}
public void AIMove(){
Random randomInt = new Random ();
boolean tryRemove = true;
while(tryRemove && totalSticks >= 1){
int RandomRow = randomInt.nextInt(3);
if(Sticks[RandomRow] <= 0)//the computer can't remove from this row
continue;
//the max number to remove from row
int size = 3;
if( Sticks[RandomRow] < 3)//this row have least that 3 cards
size = Sticks[RandomRow];//make the max number to remove from the row be the number of cards on the row
int RandomDiscard = randomInt.nextInt(size) + 1;
Sticks[RandomRow] = Sticks[RandomRow] - RandomDiscard;
//I don't know if this is needed, but since we remove a RandomDiscard amount lest decrease the totalSticks
totalSticks = totalSticks - RandomDiscard;
//exit loop
tryRemove = false;
}
if(totalSticks <= 1){
int RandomRow = 0;
Sticks[RandomRow] = Sticks[RandomRow]-1;
isOver();
}
}
}
My issue is I really don't understand the syntax.
There is nothing wrong with the syntax as you have written it.
The problem is that you are catching the exception at the wrong place. You are (apparently) intending play to propagate the IllegalSticksException to its caller. But that won't happen because you are catching it within the play method.
There are two possible fixes depending on what you actually intent to happen.
You could remove the throws IllegalSticksException from the play signature.
You could remove the catch (IllegalSticksException ex){ ... } in play and catch/handle the exception at an outer level.