I am creating a program that takes an input file, parses that information and builds a GUI calculator from that information. Currently the program works well except for when I implement an ActionListener on buttons that should set a text field to the value of the buttons getText() method.
I have tried a few different loop constructions using for and while, but all of them I have implemented have not found the where i or a counter is equal to the parsed int from numPad.getText() or returned 0 for all of the buttons.
The problem I am having while testing is that the variable i never matches numPoint. Logically my approach is to decrement i so that the loop will continue to look for matches, but never does this. The test output statements infinite loop "-1" for i and "7" for numPoint. As a note, the numPad array is not in order but instead the elements are as follows {7, 8, 9, 4, 5, 6, 1, 2, 3, 0}.
I realize that this loop may not be logically correct, but I am having a hard time finding a solution that works. I want to avoid hard coding if statements (such as i == Integer(parseInt.numPad[0].getText()) which would work.
This is the loop that creates the new buttons and adds them to an Array, sets the text based on a list created from the values of the input file and adds an ActionListener.
for (int i = 0; i < run.buttons.size(); i++) {
numPad[i] = new JButton();
numPad[i].setText(run.buttons.get(i));
numPad[i].addActionListener(new ButtonActionListener());
panel1.add(numPad[i]);
}
This is the most recent attempt at creating a loop that should make the assignment.
public static class ButtonActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int i;
int numPoint;
for (i = 0; i < numPad.length; i++) {
numPoint = Integer.parseInt(numPad[i].getText());
if (i == numPoint) {
//Match, assign
System.out.println("works");
break;
} else {
//Decrement and continue
i--;
System.out.println("test statement" + i + " " + numPoint);
continue;
}
}
}
}
There are several ways you might do this, but let's start with the basics
for (int i = 0; i < run.buttons.size(); i++) {
numPad[i] = new JButton();
numPad[i].setText(run.buttons.get(i));
// You don't "have" to do this, as the action command defaults
// to the text of the button, but this is away to provide some
// kind of identifier to the action which might be
// different from the text
numPad[i].setActionCommand(run.buttons.get(i))
numPad[i].addActionListener(new ButtonActionListener());
panel1.add(numPad[i]);
}
Then in your ActionListener...
public static class ButtonActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
int numPoint = Integer.parseInt(command);
// Perform what ever action you need
}
Related
I am making a simple calculator using a JFrame and JButtons. Before I made each button, 0 thru 9, with their own action listeners, now I have realized that this is super inefficient and I should use a loop to make each button and assign the ActionListeners. So the only thing that needs to happen in each ActionListener is to add whatever number the button is to a JTextField, called nums. Here is what I have now.
for(int i = 0; i <=9; i++) {
count = i;
btns.get(i).addActionListener(new ActionListener(){ //makes action listeners for each button
public void actionPerformed(ActionEvent e){
nums.setText(nums.getText()+ count);//IMPORTANT CODE
}
});
}
So as you can see I used a terribly named variable named count. count is set to i in each iteration before the important code is used. I have to do this because an AL is it's own class and cannot access i. However count is public and static, so the ALs can use count.
My problem is that all the buttons print 9. This logically makes sense because what is happening is that the ALs in each button use the count variable, when the loop is done, count will be 9, which means each AL will essentially contain nums.setText(nums.getText()+ 9);. Instead, I need button 1 to be nums.setText(nums.getText()+ 1); 2 to be 2, ETC.
I have tried to call the text of each button, however, because you need to use an index in the ArrayList get method, you need a variable, if you use count, the same problem occurs; after the for loops has terminated, count is 9, so all the buttons print the text of the 9 button.
Any and all help is appreciated, Thanks in advance,
-Max
P.S. Just in case you don't understand why I'm getting the text and then adding count, it is because in order to type the number 12. you need to type 1 and then concatenate the 2 to the one to et 12. getText gets the 1, and adding count concatenates the 2 to make 12.
In general you will want to avoid using static fields as you loose all benefits of object-oriented programming by this. There are specific places for use of static fields, but this is not one of them. In your situation you can't use the index of the loop, i, directly since it is not a final local variable, and non-final local variables cannot be used within anonymous inner classes. So a simple solution exists:
Make count a final local variable and you should be able to use it within your anonymous inner class:
for(int i = 0; i <= 9; i++) {
final int finalCount = i;
btns.get(i).addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
nums.setText(nums.getText() + finalCount);
}
});
}
Assuming the text for each button is simply the digit you wish to append, there is another way that lets you share the same ActionListener instance for every number button.
private ActionListener numberBtnListener = new ActionListener(){
public void actionPerformed(ActionEvent e){
JButton b = (JButton) e.getSource();
nums.setText(nums.getText() + b.getText());
}
}
Then just use the same listener instance for each button:
for(JButton b : btns) {
b.addActionListener(numberBtnListener);
}
If your button text is different for some reason, you can still use the same technique by using a client property on each button to hold the value that you wish to append. E.g.:
b.putClientProperty("digit", i);
then use
nums.setText(nums.getText() + b.getClientProperty("digit"));
I'm trying to create a simple Java GUI window in which when I a number is placed in the window, the program determines what the value of the number is (ie greater than 2, or less than 2), and then executes an autoclick depending on the int value.
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
for (int field = 0; field <= 2; field++) {
if (field <= 2) {
(EXECUTE AUTOCLICK;
}
else if ( field >= .15 ) {
do nothing
Obviously it's broken and the 'EXECUTE AUTOCLICK' is not a function, but I figured i'd put it in to show what i'm trying to accomplish.
Additionally, how would I add an auto click function into the code and where would I add it?
Can you tell tell that I'm a noob?
This question already has answers here:
Can you recommend a Java library for reading (and possibly writing) CSV files? [closed]
(8 answers)
Closed 6 years ago.
So I have received quite a few tips and acquired some resources for learning Java since joining this community. I have now reached week 6 in my class and am working through my third project. I feel like I'm learning a lot but I also have a long road ahead if I want to master Java.
My question this time is how do I get my code to save more than one output to file?
Part of my current project is to do the following:
"When the window is closed, the efficiency values should be computed with >values of n from 0 to 10 and written to a file. Each line of the file > >should contain the value of n, the efficiency of the iterative method for >that value of n and the efficiency of the recursive method. The values >should be separated by commas so the file can be opened with Excel."
I have managed to get the program to write a single entry into the output file. However,I either made an error in the code or missing something critical. Can someone point me to the correct solution? I think I may have to create an array, store the outputs there, then output the array to csv. I have looked at roseindia and viralpatel but those didn't reveal what I was hoping.
Sequence (part I'm screwing up)
package cmisproject3;
public class Sequence {
private static int efficiency = 0;
// method to compute iterative
public static int computeIterative(int n) {
int result = 0;
efficiency = 0;
if (n == 0) {
result = 0;
} else if (n == 1) {
result = 1;
} else {
int secondPrevious = 0;
int previous = 1;
for (int i = 2; i <= n; i++) {
efficiency++;
result = 2 * previous + secondPrevious;
secondPrevious = previous;
previous = result;
}
}
return result;
}
// method to comopute recursive
public static int computeRecursive(int n) {
efficiency = 0;
return computeRecursiveHelper(n);
}
private static int computeRecursiveHelper(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
efficiency++;
return 1;
} else {
efficiency++;
return 2 * computeIterative(n - 1) + computeIterative(n - 2);
}
}
public static int getEfficiency() {
return efficiency;
}
}
GUI (nailed it?)
package cmisproject3;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.*;
public class CMISProject3 extends JFrame implements ActionListener {
private final int TWICE = 2;
private JLabel jLabel1 = new JLabel(), jLabel2 = new JLabel(), jLabel3 = new JLabel(), jLabel4 = new JLabel(), jLabel5 = new JLabel(), jLabel6 = new JLabel();
private ButtonGroup radioButtons = new ButtonGroup();
private JRadioButton iterativeBtn = new JRadioButton(), recursiveBtn = new JRadioButton();
private JTextField enterN = new JTextField(16), textResult = new JTextField(16), textEfficiency = new JTextField(16);
private JButton computeBtn = new JButton();
private int efficiency;
private Sequence sequence;
private static FileWriter fileWriter;
private File file = new File("output.txt");
// Beginning of the constructor for the GUI
public CMISProject3() throws IOException {
sequence = new Sequence();
setSize(300, 200); // define size of GUI
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(6, 2));
getContentPane().add(jLabel4);
radioButtons.add(iterativeBtn);
iterativeBtn.setSelected(true); // sets Iterative as default GUI selection
iterativeBtn.setText("Iterative");
getContentPane().add(iterativeBtn);
getContentPane().add(jLabel5);
radioButtons.add(recursiveBtn);
recursiveBtn.setText("Recursive");
getContentPane().add(recursiveBtn);
jLabel1.setText("Enter n: ");
getContentPane().add(jLabel1);
getContentPane().add(enterN);
getContentPane().add(jLabel6);
computeBtn.setText("Compute");
computeBtn.addActionListener(this);
getContentPane().add(computeBtn);
jLabel2.setText("Result: ");
getContentPane().add(jLabel2);
getContentPane().add(textResult);
textResult.setEditable(false);
jLabel3.setText("Efficiency: ");
getContentPane().add(jLabel3);
getContentPane().add(textEfficiency);
textEfficiency.setEditable(false);
pack();
}
public void actionPerformed(ActionEvent event) {
int result;
efficiency = 0;
try {
fileWriter = new FileWriter(file);
} catch (IOException e1) {
e1.printStackTrace();
}
if (iterativeBtn.isSelected()) {
result = sequence.computeIterative(Integer.parseInt(enterN.getText()));
} else {
result = sequence.computeRecursive(Integer.parseInt(enterN.getText()));
}
try {
System.out.println(result);
fileWriter.write(result + ", " + sequence.getEfficiency());
} catch (IOException e) {
e.printStackTrace();
}
textResult.setText(Integer.toString(result));
textEfficiency.setText(Integer.toString(sequence.getEfficiency()));
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
CMISProject3 CMISProject3 = new CMISProject3();
CMISProject3.setVisible(true);
}
}
For those interested, here are the parameters I'm working within.
Instructions
You are reopening the file each time an action was performed without telling FileWriter to append instead of overwrite.
See:
https://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html#FileWriter(java.io.File,%20boolean)
I think you have a good start on your project. However, I see other problems apart from your question.
First I'll address your question then move on to other items. I assume when you say:
write a single entry into the output file
that you're saying you are able to write a single line to the file. So that would mean your question is: How can I write multiple lines to a file?
In that case you have at least two options. One is to setup your FileWriter to append rather than the default behavior of overwriting the existing file content.
Another option would be to avoid closing the FileWriter until you're finished writing. You could, for example, do this by moving the construction of your fileWriter to the constructor of your GUI and moving the call to the close method into an event handler that fires when the GUI closes.
Whatever you chose to do, you need to remember to write the newline character at the end of each line or else your file will be one very long line. So, modifying what you have now it would look like this:
fileWriter.write(result + ", " + sequence.getEfficiency()+"\n");
Other Issues:
Your Sequence.computeRecursiveHelper method is not recursive. A recursive method calls itself, yours does not do this.
I don't think you're following the instructions correctly. Perhaps you're just not finished yet and you intend to modify your code. If that is the case you can ignore what I'm about to point out. The instructions state:
When the window is closed, the efficiency values should be computed with values of n from 0 to 10 and written to a file.
You are currently writing to the file every time the user clicks the "Compute" button rather than doing the above. Also, you're not writing the correct data - you're writing the value you got based on the user's input not values obtained using n from 0 to 10.
I have a simple fact app that has an array of different facts.
I have a next, previous, and home button.
When the home button is pressed, I want the first fact to be displayed again, and after, it will start incrementing again from the first array value.
My home button is not working. If I hit the next button 5 times, then hit the home button, I will be directed to the first fact, but if I hit the next button, then the 6th fact will display, not the second.
Here is my code:
public String nextFact() {
i++;
if(i >= facts.length) {
i = 0;
}
return facts[i];
}
public String previousFact() {
i--;
if(i < 0) {
i = facts.length - 1;
}
return facts[i];
}
public String homeButton() {
int i = 0;
return facts[i];
}
You are declaring a new local version of i.
It should be:
public String homeButton() {
i = 0;
return facts[i];
}
According to your code, I am assuming i is a variable shared across the three methods, which keeps track of the index of the question currently displayed. If that is the case, your method should reset the class member i to 0, instead of creating a local variable.
public String homeButton() {
i = 0;
return facts[i];
}
This should do the trick.
I basically checked out a book from the Library and started learning Java. I'm trying to code a little score calculator for my golf league and this site has been a lof of help! So thanks for even being here!
Now to the question:
I have a 9 labels, created with NetBeans GUI, with names like jLabel_Hole1, jLabel_Hole2, ...
If a user selects the radio option to play the front nine those labels have number 1 - 9 and if they change it to the "Back Nine" then they should display 10 - 18. I can manually set each label to the new value on a selection change but I wanted to know if there was a more elegant way and if so if one of you could be kind enough to explain how it works.
Here is the code that I want to try and truncate:
TGL.jLbl_Hole1.setText("10");
TGL.jLbl_Hole2.setText("11");
TGL.jLbl_Hole3.setText("12");
TGL.jLbl_Hole4.setText("13");
TGL.jLbl_Hole5.setText("14");
TGL.jLbl_Hole6.setText("15");
TGL.jLbl_Hole7.setText("16");
TGL.jLbl_Hole8.setText("17");
TGL.jLbl_Hole9.setText("18");
I've read some things about String being immutable and maybe it's just a limitation but I would think there has to be way and I just can't imagine it.
Thanks.
Basically, rather then creating a individual label for each hole, you should create an array of labels, where each element in the array represents a individual hole.
So instead of...
TGL.jLbl_Hole1.setText("10");
TGL.jLbl_Hole2.setText("11");
TGL.jLbl_Hole3.setText("12");
TGL.jLbl_Hole4.setText("13");
TGL.jLbl_Hole5.setText("14");
TGL.jLbl_Hole6.setText("15");
TGL.jLbl_Hole7.setText("16");
TGL.jLbl_Hole8.setText("17");
TGL.jLbl_Hole9.setText("18");
You would have...
for (JLabel label : TGL.holeLables) {
lable.setText(...);
}
A better solution would be to hide the labels from the developer and simply provide a setter...
TGL.setHoleText(hole, text); // hole is int and text is String
Internally to your TGL class, you have two choices...
If you've used the form editor in Netbeans, you're going to have to place the components that Netbeans creates into your own array...
private JLabel[] holes;
//...//
// Some where after initComponents is called...
holes = new JLabel[9];
holes[0] = jLbl_Hole1;
// There other 8 holes...
Then you would simply provide a setter and getter methods that can update or return the value...
public void setHole(int hole, String text) {
if (hole >= 0 && hole < holes.length) {
holes[hole].setText(text);
}
}
public String getHole() {
String text = null;
if (hole >= 0 && hole < holes.length) {
text = holes[hole].getText();
}
return text;
}
Take a closer look at the Arrays tutorial for more details...
I've never found a Java GUI-generator to provide code that's any good. I may be wrong--there may be a good one, but I always prefer to position and name them myself. So,
/**
* The JLabels for the holes on the golf course.
* <p>
* holeLabels[0][i] are for the outward holes, 1-9.
* holeLabels[1][i] are for the inward holes, 10-18.
*/
private JLabel[][] holeLabels;
/**
* The starts of the outward and inward ranges of holes.
*/
private static final int[] holeStart = {1, 10};
// Later
holeLabels = new JLabel[2][9];
for(final int i = 0; i < holeLabels.length; i++) {
for (final int j = 0; j < holeLabels[i].length; j++) {
holeLabel[i][j] = new JLabel();
holeLabel[i][j].setText(Integer.toString(holeStart[i] + j));
}
}
Interestingly, holeLabels.length is 2. holeLabels is an array of 2 arrays of 9 ints. i goes from 0 to 1, and j goes from 0 to 8, so the text computation works. The reason I did things this way is so you can easily place the labels in an appropriate GridLayout later.