Reputation: 13
I am somewhat new to java, and especially swing interfaces. I am trying to make it where if you enter a number after having the result of two numbers displayed, it will just clear it and replace it with the next number you press. For example, if you added 1 + 2 and then it displayed 3, if you pressed the number 4 for example, it would clear the number 3 and replace it with 4.
The next pressing issue is when i do add two numbers using the addition case switch, it works fine besides the fact that it will display the second number along with the result of the two added numbers. So for example, if you added 1 + 2, it will show "23", where the two was the last number in the sum, and the number three is the result of the summation. Any help?
package javacalc;
import com.sun.source.tree.BreakTree;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CalcGUI extends JFrame implements ActionListener {
final static String PROJ_TITLE = "Calculator";
final static String PROJ_AUTHORS = String.format("Jaren Browne%nKevin Miller");
final static int[] PROJ_WINDOW_SIZE = {490, 650};
final static int[] PROJ_WINDOW_LOCATION = {300, 300};
GridBagConstraints gbcCalcPanel = new GridBagConstraints();
GridBagConstraints gbcButtonPanel = new GridBagConstraints();
JPanel calcPanel = new JPanel();
JTextField upperDisplay;
JTextField lowerDisplay;
private int operation = 0;
private boolean clearScreen = false;
private double firstNumber = 0;
private double secondNumber = 0;
DecimalFormat df = new DecimalFormat("0.##############");
@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
switch (command) {
case ".": // decimal
updateDisplay(command);
break;
case "=": // equal
if (!upperDisplay.getText().equals("0")) {
secondNumber = Double.parseDouble(upperDisplay.getText());
switch (operation) {
case 2: // addition
updateDisplay(String.valueOf(df.format(firstNumber + secondNumber)));
break;
case 3: // subtraction
upperDisplay.setText(String.valueOf(df.format(firstNumber - secondNumber)));
break;
case 4: // multiplication
upperDisplay.setText(String.valueOf(df.format(firstNumber * secondNumber)));
break;
case 5: // division
upperDisplay.setText(String.valueOf(df.format(firstNumber / secondNumber)));
break;
case 6: // percent ( firstNumber % secondNumber = firstNumber% of secondNumber )
upperDisplay.setText(String.valueOf(df.format(((firstNumber / 100) * secondNumber))));
break;
case 7:
if (firstNumber == 0) { firstNumber = 1; }
upperDisplay.setText(String.valueOf(df.format(firstNumber * Math.sqrt(secondNumber))));
break;
case 8:
// upperDisplay.setText(String.valueOf(df.format()));
break;
case 9:
// upperDisplay.setText(String.valueOf(df.format()));
break;
}
}
break;
case "+": // add
firstNumber = Double.parseDouble(upperDisplay.getText());
operation = 2;
clearScreen = true;
break;
case "-": // subtract
firstNumber = Double.parseDouble(upperDisplay.getText());
operation = 3;
clearScreen = true;
break;
case "x": // multiply
firstNumber = Double.parseDouble(upperDisplay.getText());
operation = 4;
clearScreen = true;
break;
case "÷": // divide
firstNumber = Double.parseDouble(upperDisplay.getText());
operation = 5;
clearScreen = true;
break;
case "%": // percent
firstNumber = Double.parseDouble(upperDisplay.getText());
operation = 6;
clearScreen = true;
break;
// FIXME - +/- should not leave only '-' char when delete is pressed on last digit
// FIXME - if there is only one digit and it is not 0, and the - is active
// FIXME - it should not remove the last character and only leave -
// FIXME - it should change last remaining character to 0 and unalive the -
case "+/-": // negate
upperDisplay.setText(upperDisplay.getText().equals("0")||
(upperDisplay.getText().length() == 1 && upperDisplay.getText().equals("0"))?
"0":String.valueOf(df.format(Double.parseDouble(upperDisplay.getText()) * -1)));
break;
case "√": // square root
firstNumber = Double.parseDouble(upperDisplay.getText());
operation = 7;
clearScreen = true;
break;
case "xⁿ": // exponent
break;
case "ⁿ√": // exponent root
break;
case "π": // pi
break;
case "sin": // sine
break;
case "cos": // cosine
break;
case "tan": // tangent
break;
case "sin‾¹": // arcsine
break;
case "cos‾¹": // arccosine
break;
case "tan‾¹": // arctan
break;
case "<-": // backspace
deletePressed();
break;
case "CE": // clear
firstNumber = 0;
secondNumber = 0;
operation = 0;
clearScreen = false;
upperDisplay.setText("0");
// lowerDisplay.setText("0");
break;
case "M+": // mem+
break;
case "M-": // mem-
break;
case "MC": // mem clear
break;
default:
break;
}
}
public CalcGUI() {
initGUI();
calcPanel.setLayout(new GridBagLayout());
// add display box
gbcCalcPanel.gridx = 0;
gbcCalcPanel.gridy = 0;
gbcCalcPanel.fill = GridBagConstraints.HORIZONTAL;
gbcCalcPanel.gridwidth = 1;
calcPanel.add(upperDisplay = buildDisplay(), gbcCalcPanel);
// // add second display box
// gbcCalcPanel.gridx = 0;
// gbcCalcPanel.gridy = 1;
// gbcCalcPanel.fill = GridBagConstraints.HORIZONTAL;
// gbcCalcPanel.gridwidth = 1;
// calcPanel.add(lowerDisplay = buildDisplay(), gbcCalcPanel);
// add advanced calculator buttons
gbcCalcPanel.gridx = 0;
gbcCalcPanel.gridy = 2;
gbcCalcPanel.weighty = 1;
gbcCalcPanel.fill = GridBagConstraints.BOTH;
calcPanel.add(buildAdvancedButtonPanel(), gbcCalcPanel);
// add calculator buttons
gbcCalcPanel.gridx = 0;
gbcCalcPanel.gridy = 3;
gbcCalcPanel.weighty = 1;
gbcCalcPanel.fill = GridBagConstraints.BOTH;
calcPanel.add(buildButtonPanel(), gbcCalcPanel);
setContentPane(calcPanel);
pack();
}
// BUILD DISPLAY BOX
private JTextField buildDisplay() {
JTextField t = new JTextField("", 16);
t.setHorizontalAlignment(SwingConstants.RIGHT);
t.setBackground(Color.DARK_GRAY);
t.setForeground(Color.GREEN);
t.setText("0");
t.setCaretPosition(1);
try {
Font calcDisplayFont = Font.createFont(Font.TRUETYPE_FONT, new File("src\\font\\DS-DIGII.TTF")).deriveFont(60f);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(calcDisplayFont);
t.setFont(calcDisplayFont);
} catch (IOException | FontFormatException e) {
System.out.println(e.getMessage());
Font calcDisplayFont = new Font("Lucida Console", Font.BOLD, 40);
t.setFont(calcDisplayFont);
}
return t;
}
// BUILD BUTTON PANEL
private JPanel buildButtonPanel() {
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.setBackground(Color.gray);
String[][] buttonText = {{"MC", "MR", "M-", "M+", "÷"},
{"+/-", "7", "8", "9", "x"},
{"%", "4", "5", "6", "-"},
{"√", "1", "2", "3", "+"},
{"CE", "0", ".", "=", "+"}};
int maxWidth = buttonText[0].length;
int maxHeight = buttonText.length;
JButton[][] calcButton = new JButton[maxHeight][maxWidth];
// cycle through button array and build
for (int yPos = 0; yPos < maxHeight; yPos++) {
for (int xPos = 0; xPos < maxWidth; xPos++) {
// build button panel, skipping button for extended '+' button
if (!(yPos == 4 && xPos == 4)) {
calcButton[yPos][xPos] = new JButton(buttonText[yPos][xPos]);
calcButton[yPos][xPos].setFont(calcButton[yPos][xPos].getFont().deriveFont(30f));
calcButton[yPos][xPos].setBackground(Color.black);
// test if button pressed is number or operation
// if number, send to display
if (calcButtonTest(buttonText[yPos][xPos])) {
String calcValue = calcButton[yPos][xPos].getText();
calcButton[yPos][xPos].addActionListener(e -> updateDisplay(calcValue));
} else {
calcButton[yPos][xPos].addActionListener(this);
}
gbcButtonPanel.gridx = xPos;
gbcButtonPanel.gridy = yPos;
gbcButtonPanel.gridwidth = 1;
gbcButtonPanel.weightx = 1;
gbcButtonPanel.weighty = 1;
Insets buttonSpacing = new Insets(2,2,2,2);
gbcButtonPanel.insets = buttonSpacing;
// if the button being added is '+' extended it vertically
if (yPos == 3 && xPos == 4) {
gbcButtonPanel.gridheight = 2;
gbcButtonPanel.fill = GridBagConstraints.BOTH;
} else {
gbcButtonPanel.gridheight = 1;
gbcButtonPanel.fill = GridBagConstraints.BOTH;
}
panel.add(calcButton[yPos][xPos], gbcButtonPanel);
}
}
}
return panel;
}
private JPanel buildAdvancedButtonPanel() {
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.setBackground(Color.darkGray);
String[][] buttonText = {{"<-", "xⁿ", "sin", "cos", "tan"},
{"π", "ⁿ√", "sin‾¹", "cos‾¹", "tan‾¹"}};
int maxWidth = buttonText[0].length;
int maxHeight = buttonText.length;
JButton[][] calcButton = new JButton[maxHeight][maxWidth];
// cycle through button array and build
for (int yPos = 0; yPos < maxHeight; yPos++) {
for (int xPos = 0; xPos < maxWidth; xPos++) {
calcButton[yPos][xPos] = new JButton(buttonText[yPos][xPos]);
calcButton[yPos][xPos].setFont(calcButton[yPos][xPos].getFont().deriveFont(30f));
calcButton[yPos][xPos].addActionListener(this);
gbcButtonPanel.gridx = xPos;
gbcButtonPanel.gridy = yPos;
gbcButtonPanel.gridwidth = 1;
gbcButtonPanel.weightx = 1;
gbcButtonPanel.weighty = 1;
gbcButtonPanel.gridheight = 1;
Insets buttonSpacing = new Insets(2,2,2,2);
gbcButtonPanel.insets = buttonSpacing;
gbcButtonPanel.fill = GridBagConstraints.BOTH;
panel.add(calcButton[yPos][xPos], gbcButtonPanel);
}
}
return panel;
}
// INITIALIZE GUI LOOK AND FEEL
private void initGUI() {
try {
// sets the look and feel to that of the OS if possible
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
// tell us a story
System.out.printf("Unable to load GUI.%n%s%n", e.getMessage());
}
// set some window and frame options
setTitle(PROJ_TITLE);
// setPreferredSize(new Dimension(PROJ_WINDOW_SIZE[0], PROJ_WINDOW_SIZE[1]));
setResizable(false);
setLocation(PROJ_WINDOW_LOCATION[0], PROJ_WINDOW_LOCATION[1]);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private boolean calcButtonTest(String s) {
try {
Integer.parseInt(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
// UPDATE DISPLAY
private void updateDisplay(String s) {
StringBuilder displayString = new StringBuilder();
System.out.println(s);
if (clearScreen) {
upperDisplay.setText("");
clearScreen = false;
}
if (Double.parseDouble(s) < 0) {
System.out.println("neg");
}
if (upperDisplay.getText().length() + 1 <= 15) {
// DECIMAL HANDLER
if (s.equals(".")){
if (!upperDisplay.getText().contains(s)) {
if (upperDisplay.getText().equals("0")) {
upperDisplay.setText(String.format("0%s", s));
} else {
upperDisplay.setText(String.format("%s", upperDisplay.getText() + s));
}
}
} else {
if (upperDisplay.getText().equals("0")) {
upperDisplay.setText(String.format("%s", s));
} else {
upperDisplay.setText(String.format("%s", upperDisplay.getText() + s));
}
}
}
}
// DELETE LAST CHARACTER
private void deletePressed(){
int l = upperDisplay.getText().length();
int n = upperDisplay.getText().length() - 1;
if (l > 1) {
StringBuilder backSpace = new StringBuilder(upperDisplay.getText());
upperDisplay.setText(backSpace.deleteCharAt(n).toString());
} else {
upperDisplay.setText("0");
}
}
}
Even though it may seem like everything is out of whack, every other basic operator works just fine. Multiplication, division, and subtraction work fine.
Upvotes: 0
Views: 67
Reputation: 86
Specifically for your problem, where the behavior of the +
operation
is different than the others, is explained by a discrepancy in your switch
statement.
The calls for operation
3 and greater (the ones that are implemented in this snippet) all directly invoke upperDisplay.setText(...)
and result in the upper display output being overridden. Your code for the +
operation is instead calling your method updateDisplay(...)
which has additional logic, and won't directly replace the text of that upper display.
If you replace
case 2: // addition
updateDisplay(String.valueOf(df.format(firstNumber + secondNumber)));
break;
with
case 2: // addition
upperDisplay.setText(String.valueOf(df.format(firstNumber + secondNumber)));
break;
then the behavior for +
should be consistent with the rest.
However, this implementation also doesn't appear to clear your display when you start entering another another calculation (e.g. after 1
+
2
outputs 3
, pressing 4
will lead to your display presenting 34
and 34
ends up getting parsed as your next "first" number rather than 4
).
You may want to consider appending the following at the end of your switch statement:
if (!upperDisplay.getText().equals("0")) {
secondNumber = Double.parseDouble(upperDisplay.getText());
switch(operation) {
...
}
clearScreen = true; // <- add this
}
so that you can seamlessly transition to entering your next calculation.
Upvotes: 1