Skip to content

Instantly share code, notes, and snippets.

@jewelsea
Last active September 13, 2023 19:31
  • Star 17 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jewelsea/4344564 to your computer and use it in GitHub Desktop.
A simple JavaFX calculator
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.*;
import java.util.*;
// a simple JavaFX calculator.
public class Calc extends Application {
private static final String[][] template = {
{"7", "8", "9", "/"},
{"4", "5", "6", "*"},
{"1", "2", "3", "-"},
{"0", "c", "=", "+"}
};
private final Map<String, Button> accelerators = new HashMap<>();
private final DoubleProperty stackValue = new SimpleDoubleProperty();
private final DoubleProperty value = new SimpleDoubleProperty();
private enum Op {NOOP, ADD, SUBTRACT, MULTIPLY, DIVIDE}
private Op curOp = Op.NOOP;
private Op stackOp = Op.NOOP;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
final TextField screen = createScreen();
final TilePane buttons = createButtons();
stage.setTitle("Calc");
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: chocolate; -fx-padding: 20; -fx-font-size: 20;");
layout.getChildren().setAll(screen, buttons);
handleAccelerators(layout);
screen.prefWidthProperty().bind(buttons.widthProperty());
return layout;
}
private void handleAccelerators(VBox layout) {
layout.addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> {
Button activated = accelerators.get(keyEvent.getText());
if (activated != null) {
activated.fire();
}
});
}
private TextField createScreen() {
final TextField screen = new TextField();
screen.setStyle("-fx-background-color: aquamarine;");
screen.setAlignment(Pos.CENTER_RIGHT);
screen.setEditable(false);
screen.textProperty().bind(Bindings.format("%.0f", value));
return screen;
}
private TilePane createButtons() {
TilePane buttons = new TilePane();
buttons.setVgap(7);
buttons.setHgap(7);
buttons.setPrefColumns(template[0].length);
for (String[] r : template) {
for (String s : r) {
buttons.getChildren().add(createButton(s));
}
}
return buttons;
}
private Button createButton(final String s) {
Button button = makeStandardButton(s);
if (s.matches("[0-9]")) {
makeNumericButton(s, button);
} else {
final ObjectProperty<Op> triggerOp = determineOperand(s);
if (triggerOp.get() != Op.NOOP) {
makeOperandButton(button, triggerOp);
} else if ("c".equals(s)) {
makeClearButton(button);
} else if ("=".equals(s)) {
makeEqualsButton(button);
}
}
return button;
}
private ObjectProperty<Op> determineOperand(String s) {
final ObjectProperty<Op> triggerOp = new SimpleObjectProperty<>(Op.NOOP);
switch (s) {
case "+" -> triggerOp.set(Op.ADD);
case "-" -> triggerOp.set(Op.SUBTRACT);
case "*" -> triggerOp.set(Op.MULTIPLY);
case "/" -> triggerOp.set(Op.DIVIDE);
}
return triggerOp;
}
private void makeOperandButton(Button button, final ObjectProperty<Op> triggerOp) {
button.setStyle("-fx-base: lightgray;");
button.setOnAction(actionEvent -> curOp = triggerOp.get());
}
private Button makeStandardButton(String s) {
Button button = new Button(s);
button.setStyle("-fx-base: beige;");
accelerators.put(s, button);
button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
return button;
}
private void makeNumericButton(final String s, Button button) {
button.setOnAction(actionEvent -> {
if (curOp == Op.NOOP) {
value.set(value.get() * 10 + Integer.parseInt(s));
} else {
stackValue.set(value.get());
value.set(Integer.parseInt(s));
stackOp = curOp;
curOp = Op.NOOP;
}
});
}
private void makeClearButton(Button button) {
button.setStyle("-fx-base: mistyrose;");
button.setOnAction(actionEvent -> value.set(0));
}
private void makeEqualsButton(Button button) {
button.setStyle("-fx-base: ghostwhite;");
button.setOnAction(actionEvent -> {
switch (stackOp) {
case ADD -> value.set(stackValue.get() + value.get());
case SUBTRACT -> value.set(stackValue.get() - value.get());
case MULTIPLY -> value.set(stackValue.get() * value.get());
case DIVIDE -> value.set(stackValue.get() / value.get());
}
});
}
}
@jewelsea
Copy link
Author

Oracle JavaFX forum thread: Simple calculator control. Anyone ?

@jewelsea
Copy link
Author

jewelsea commented Oct 1, 2014

Note, as the title says, this is a very simple calculator. It does not handle things like non-integral values and operator precedence, memory recall, bracketed expressions, etc. It's just basic add, subtract, multiply divide immediately applied on the latest displayed value.

@jewelsea
Copy link
Author

jewelsea commented Oct 1, 2014

This is coded as a single Java file - a more flexible design would be to have the layout in FXML, the styling in an external CSS stylesheet and the calculator logic less intertwined with the UI display.

@XiyunLiu
Copy link

XiyunLiu commented Mar 8, 2016

It doesn't work for sth like "1+2*3"

@jewelsea
Copy link
Author

jewelsea commented Apr 1, 2016

Yes xiyun, I already noted that "It does not handle things like non-integral values and operator precedence". Feel free to fork the code and add such functionality if you wish.

@azzamsa
Copy link

azzamsa commented Apr 24, 2017

thanks lot for this javafx introduction, Jewelsea

@hamilbrian
Copy link

Good stuff!

@jewelsea
Copy link
Author

For anybody who would like to improve the operation of this calculator, you could look at combining its operation with an implementation of the shunting-yard algorithm as a basis for providing the capability to handle operator precedence by converting the input to reverse polish notation and then evaluating it.

@Felixnkumbira
Copy link

it is giving me 9 errors

@Nicleonic
Copy link

thx bro

@Kapil-Joban
Copy link

Can anybody tell us how can we make the sum of more than two numbers in above mentioned code?

@sedj601
Copy link

sedj601 commented Sep 13, 2023

Can anybody tell us how can we make the sum of more than two numbers in above mentioned code?

@Kapil-Joban did you read @jewelsea's comment dated Mar 9, 2018? The shunting-yard algorithm is proposed in that comment.

@sedj601
Copy link

sedj601 commented Sep 13, 2023

Can anybody tell us how can we make the sum of more than two numbers in above mentioned code?

@Kapil-Joban , You can also have a look at javax ScriptEngineManager. I guess it still works. I am not sure. https://github.com/sedj601/CalculatorFX2/blob/master/CalculatorController.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment