Code
package sample;
import java.util.Stack;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import java.util.Map; // Used maps to utilize ease with buttons
import java.util.HashMap;
// Stack / pop calculator with style
public class Main extends Application
{
// Basic grid pattern for calculator
private static final String[][] image =
{
{ "7", "8", "9", "/" },
{ "4", "5", "6", "*" },
{ "1", "2", "3", "-" },
{ "0", "C", "=", "+" }
};
// Mapping calculator keys
private final Map<String, Button> menuKeys = new HashMap<>();
// Stack
private Stack<String> stackValue = new Stack<>();
// Current value entered
private double valueHolderCurrent = 0;
// Current value on stack
private double valueHolderOnStack = 0;
// Values added
private double valuesAdded = 0;
private enum Operations
{
BLANK, ADD, SUBTRACT, MULTIPLY, DIVIDE
}
private Operations currentOperator = Operations.BLANK;
private Operations onStackOperator = Operations.BLANK;
public static void main(String[] args)
{
launch(args);
}
@Override public void start(Stage stage)
{
final TextField screen = createScreen();
final TilePane buttons = createButtons();
stage.setTitle("Calculator");
stage.initStyle(StageStyle.UTILITY);
stage.setResizable(false);
stage.setScene(new Scene(createLayout(screen, buttons)));
stage.show();
}
private VBox createLayout(TextField screen, TilePane buttons)
{
final VBox layout = new VBox(20);
layout.setAlignment(Pos.CENTER);
layout.setStyle("-fx-background-color: steelblue; -fx-padding: 20; -fx-font-size: 20;");
layout.getChildren().setAll(screen, buttons);
menuKeys(layout);
screen.prefWidthProperty().bind(buttons.widthProperty());
return layout;
}
private void menuKeys(VBox layout)
{
layout.addEventFilter(KeyEvent.KEY_PRESSED, keyEvent ->
{
Button instantiated = menuKeys.get(keyEvent.getText());
if (instantiated != null)
{
instantiated.fire();
}
})
;
}
private TextField createScreen()
{
final TextField screen = new TextField();
screen.setStyle("-fx-background-color: silver;");
screen.setAlignment(Pos.CENTER_RIGHT);
screen.setEditable(false);
new ReadOnlyObjectWrapper<>( "");
return screen;
}
private TilePane createButtons()
{
TilePane buttons = new TilePane();
buttons.setVgap(5);
buttons.setHgap(5);
buttons.setPrefColumns(image[0].length);
for (String[] reImage: image)
{
for (String temp: reImage)
{
buttons.getChildren().add(createButton(temp));
}
}
return buttons;
}
private Button createButton(final String temp)
{
Button button = normalizeButton(temp);
if (temp.matches("[0-9]"))
{
numbersButton(temp, button);
}
else
{
final ObjectProperty<Operations> handleOperations = determineOperand(temp);
if (handleOperations.get() != Operations.BLANK)
{
operandButtons(button, handleOperations);
}
else if ("C".equals(temp))
{
clearButton(button);
}
else if ("=".equals(temp))
{
equalButton(button);
}
}
return button;
}
private ObjectProperty<Operations> determineOperand(String temp)
{
final ObjectProperty<Operations> handleOperations = new SimpleObjectProperty<>(Operations.BLANK);
// Determines operation to perform once operand is entered.
switch (temp)
{
case "+": handleOperations.set(Operations.ADD);
break;
case "-": handleOperations.set(Operations.SUBTRACT);
break;
case "*": handleOperations.set(Operations.MULTIPLY);
break;
case "/": handleOperations.set(Operations.DIVIDE);
break;
}
return handleOperations;
}
// Operands buttons + - / *
private void operandButtons(Button button, final ObjectProperty<Operations> handleOperations)
{
button.setStyle("-fx-base: gold;");
button.setOnAction(actionEvent -> currentOperator = handleOperations.get());
}
private Button normalizeButton(String temp)
{
Button button = new Button(temp);
button.setStyle("-fx-base: gold;");
menuKeys.put(temp, button);
button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
return button;
}
private void numbersButton(final String temp, Button button)
{
button.setOnAction(actionEvent ->
{
if (currentOperator == Operations.BLANK)
{
stackValue.push(Integer.toString( 10 + Integer.parseInt(temp)));
}
else
{
stackValue.set(Integer.parseInt(temp), "");
onStackOperator = currentOperator;
currentOperator = Operations.BLANK;
}
});
}
//Clear button to reset calculator
private void clearButton(Button button)
{
button.setStyle("-fx-base: Gold;");
button.setOnAction(actionEvent -> stackValue.push(""));
}
private void equalButton(Button button)
{
button.setStyle("-fx-base: gold;");
button.setOnAction(actionEvent ->
{
switch (onStackOperator)
{
case ADD: {
if (stackValue.peek().equals("+"))
{
valueHolderOnStack = Double.parseDouble(stackValue.peek());
stackValue.pop();
valueHolderCurrent = Double.parseDouble(stackValue.peek());
stackValue.pop();
valuesAdded = valueHolderOnStack + valueHolderCurrent;
stackValue.push("" + valuesAdded);
}
}
break;
case SUBTRACT: {
if (stackValue.peek().equals("-"))
{
valueHolderOnStack = Double.parseDouble(stackValue.peek());
stackValue.pop();
valueHolderCurrent = Double.parseDouble(stackValue.peek());
stackValue.pop();
valuesAdded = valueHolderOnStack - valueHolderCurrent;
stackValue.push("" + valuesAdded);
}
}
break;
case MULTIPLY: {
if (stackValue.peek().equals("*"))
{
valueHolderOnStack = Double.parseDouble(stackValue.peek());
stackValue.pop();
valueHolderCurrent = Double.parseDouble(stackValue.peek());
stackValue.pop();
valuesAdded = valueHolderOnStack * valueHolderCurrent;
stackValue.push("" + valuesAdded);
}
}
break;
case DIVIDE:
if (stackValue.peek().equals("/"))
{
{
valueHolderOnStack = Double.parseDouble(stackValue.peek());
stackValue.pop();
valueHolderCurrent = Double.parseDouble(stackValue.peek());
stackValue.pop();
valuesAdded = valueHolderOnStack / valueHolderCurrent;
stackValue.push("" + valuesAdded);
}
}
break;
}
});
}
}
This post was edited by Cocoo on Nov 25 2018 11:42am