I'm building a calculator in javafx and I'm attempting to implement a utility where the user can enter the formula they want to compute, instead of typing in numbers and operations one by one. The application should open a new window, the user can type in the formula and then hit calculate. Then the formula window should close and the result be displayed in the display of the main calculator.
I've created a method in my main controller that can set formula value
public void returnFormula(String _formula)
and I call the controller in the second stage. From there I plan to implement regex to calculate the formula and return the result. At the moment I just want to to return the formula as a proof of concept. But when I try to display the result it's blank; Debugging shows that the value of formula is null. How can I properly pass this value back to the main controller?
IDE: Netbeans 9.0
Java version: 1.8.0_211
Main Controller:
public class FXMLDocumentController implements Initializable {
//FXML Items
@FXML
private Button clearBttn;
@FXML
private Button signBttn;
@FXML
private Button percentBttn;
@FXML
private Button divBttn;
@FXML
private Button seven;
@FXML
private Button eight;
@FXML
private Button nine;
@FXML
private Button multBttn;
@FXML
private Button four;
@FXML
private Button five;
@FXML
private Button six;
@FXML
private Button subBttn;
@FXML
private Button one;
@FXML
private Button two;
@FXML
private Button three;
@FXML
private Button addBttn;
@FXML
private Button zero;
@FXML
private Button decimalPnt;
@FXML
private Button equalBttn;
@FXML
private MenuItem aboutPress;
@FXML
private TextField display;
@FXML
private AnchorPane anchor;
//class variables
double temp, result;
String currentNum = "",
formula;
Operation currentOp;
boolean opPressed;
@FXML
private MenuItem binaryMI;
@FXML
private MenuItem hexMI;
@FXML
private MenuItem formulaMI;
@Override
public void initialize(URL url, ResourceBundle rb) {
anchor.setOnKeyPressed((KeyEvent ev) -> { //listerner for all relevant keys
switch(ev.getCode()){
case DIGIT0:
zero.fire();
break;
case DIGIT1:
one.fire();
break;
case DIGIT2:
two.fire();
break;
case DIGIT3:
three.fire();
break;
case DIGIT4:
four.fire();
break;
case DIGIT5:
five.fire();
break;
case DIGIT6:
six.fire();
break;
case DIGIT7:
seven.fire();
break;
case DIGIT8:
eight.fire();
break;
case DIGIT9:
nine.fire();
break;
case EQUALS:
case ENTER:
equalBttn.fire();
break;
case MINUS:
subBttn.fire();
break;
case PLUS:
addBttn.fire();
break;
case SLASH:
divBttn.fire();
break;
case ASTERISK:
multBttn.fire();
break;
case PERIOD:
decimalPnt.fire();
break;
}
});
}
//NUMBER BUTTONS
@FXML
private void press7(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '7';
updateDisplay(currentNum);
}
@FXML
private void press8(ActionEvent event){
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '8';
updateDisplay(currentNum);
}
@FXML
private void press9(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '9';
updateDisplay(currentNum);
}
@FXML
private void press4(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '4';
updateDisplay(currentNum);
}
@FXML
private void press5(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '5';
updateDisplay(currentNum);
}
@FXML
private void press6(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '6';
updateDisplay(currentNum);
}
@FXML
private void press1(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '1';
updateDisplay(currentNum);
}
@FXML
private void press2(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '2';
updateDisplay(currentNum);
}
@FXML
private void press3(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '3';
updateDisplay(currentNum);
}
@FXML
private void press0(ActionEvent event) {
if(opPressed){
currentNum = "";
opPressed = false;
}
currentNum += '0';
updateDisplay(currentNum);
}
//OPERATIONAL BUTTONS
//Clear calculator
@FXML
private void clearPress(ActionEvent event) {
currentNum = "";
updateDisplay(currentNum);
temp = 0;
result = 0;
}
//alternate sign button
@FXML
private void signPress(ActionEvent event) {
if(getNum() == 0)
return;
try{
currentNum = Double.toString(getNum() * -1);
updateDisplay(currentNum);
}catch(NumberFormatException e){
numberError();
}
}
//create percent out of number
@FXML
private void percentPress(ActionEvent event) {
try{
currentNum = Double.toString(getNum() * .01);
updateDisplay(currentNum);
}catch(NumberFormatException e){
numberError();
}
}
//period button
@FXML
private void decPress(ActionEvent event) {
if(display.getText().trim().isEmpty()){
currentNum = "0.";
updateDisplay(currentNum);
}
else{
currentNum += ".";
updateDisplay(currentNum);
}
}
//MATH BUTTONS
//MULTIPLY
@FXML
private void multPress(ActionEvent event) {
currentOp = Operation.MUL;
opCheck();
}
//DIVIDE
@FXML
private void divPress(ActionEvent event) {
currentOp = Operation.DIV;
opCheck();
}
//SUBTRACT
@FXML
private void subPress(ActionEvent event) {
currentOp = Operation.SUB;
opCheck();
}
//ADD
@FXML
private void addPress(ActionEvent event) {
currentOp = Operation.ADD;
opCheck();
}
//EQUALS
@FXML
private void equalPress(ActionEvent event) {
try{
result = currentOp.math(temp, getNum());
currentNum = "";
temp = 0;
updateDisplay(result);
}
catch(NumberFormatException e){
numberError();
}
}
//INTERNAL FUNCTIONS
//checks if it's currently in an operation state
private void opCheck(){
if(!opPressed){
opPressed = true;
temp = getNum();
}
else{
opPressed = false;
equalBttn.fire();
}
}
//complete a math operations
private void completeOp(Operation _op){
try{
result = currentOp.math(result, getNum());
currentNum = "";
temp = 0;
updateDisplay(result);
}catch(NumberFormatException e){
numberError();
}
}
//get the current number from the display
private double getNum(){
return Double.parseDouble(display.getText());
}
//OVERLOADED update display using string
public void updateDisplay(String _num){
display.setText(_num);
}
//OVERLOADED UPDATE DISPLAY USING DOUBLE
private void updateDisplay(Double _num){
updateDisplay(Double.toString(_num));
}
//function to call if a number occurs, resets the calculator and present an error
private void numberError(){
Alert alert = new Alert(Alert.AlertType.ERROR, "Error parsing number input, calculator has been reset.");
alert.showAndWait();
currentNum = "";
updateDisplay(currentNum);
temp = 0;
result = 0;
}
@FXML
private void binPressed(ActionEvent event) {
if(display.getText().trim().isEmpty()){
Alert alert = new Alert(Alert.AlertType.ERROR, "Nothing to convert.");
alert.showAndWait();
return;
}
currentNum = "";
temp = 0;
result = 0;
opPressed = true;
int bin = (int)getNum();
TextField text = new TextField(Integer.toBinaryString(bin));
Stage stage = new Stage();
stage.setTitle("Binary Value");
stage.setScene(new Scene(text, 250, 25));
text.setEditable(false);
stage.setResizable(false);
stage.show();
}
@FXML
private void hexPressed(ActionEvent event) {
if(display.getText().trim().isEmpty()){
Alert alert = new Alert(Alert.AlertType.ERROR, "Nothing to convert.");
alert.showAndWait();
return;
}
currentNum = "";
temp = 0;
result = 0;
opPressed = true;
TextField text = new TextField(Double.toHexString(getNum()));
Stage stage = new Stage();
stage.setTitle("Hexedecimal Value");
stage.setScene(new Scene(text, 250, 25));
text.setEditable(false);
stage.setResizable(false);
stage.show();
}
@FXML
private void formulaPressed(ActionEvent event) {
try{
FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("/simplecalculator/FormulaInputFXML.fxml"));
Stage formStage = new Stage();
Parent root1 = (Parent) fxmlLoader.load();
formStage.setTitle("Formula Input");
formStage.setScene(new Scene(root1));
formStage.show();
}catch(IOException e){
e.printStackTrace();
}
}
public void returnFormula(String _formula) {
this.formula = _formula;
updateDisplay(this.formula);
}
}
Main FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<AnchorPane id="AnchorPane" fx:id="anchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="295.0" prefWidth="225.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="simplecalculator.FXMLDocumentController">
<children>
<GridPane alignment="CENTER" layoutY="175.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="225.0" prefWidth="225.0" AnchorPane.topAnchor="70.0">
<columnConstraints>
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Button fx:id="clearBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#clearPress" prefHeight="45.0" prefWidth="55.0" text="C" textAlignment="CENTER">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="signBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#signPress" prefHeight="45.0" prefWidth="55.0" text="+/−" textAlignment="CENTER" textOverrun="CLIP" GridPane.columnIndex="1">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="percentBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#percentPress" prefHeight="45.0" prefWidth="55.0" text="\%" textAlignment="CENTER" GridPane.columnIndex="2">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="divBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#divPress" prefHeight="45.0" prefWidth="55.0" text="÷" textAlignment="CENTER" GridPane.columnIndex="3">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="seven" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press7" prefHeight="45.0" prefWidth="55.0" text="7" textAlignment="CENTER" GridPane.rowIndex="1">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="eight" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press8" prefHeight="45.0" prefWidth="55.0" text="8" textAlignment="CENTER" GridPane.columnIndex="1" GridPane.rowIndex="1">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="nine" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press9" prefHeight="45.0" prefWidth="55.0" text="9" textAlignment="CENTER" GridPane.columnIndex="2" GridPane.rowIndex="1">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="multBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#multPress" prefHeight="45.0" prefWidth="55.0" text="X" textAlignment="CENTER" GridPane.columnIndex="3" GridPane.rowIndex="1">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="four" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press4" prefHeight="45.0" prefWidth="55.0" text="4" textAlignment="CENTER" GridPane.rowIndex="2">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="five" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press5" prefHeight="45.0" prefWidth="55.0" text="5" textAlignment="CENTER" GridPane.columnIndex="1" GridPane.rowIndex="2">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="six" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press6" prefHeight="45.0" prefWidth="55.0" text="6" textAlignment="CENTER" GridPane.columnIndex="2" GridPane.rowIndex="2">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="subBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#subPress" prefHeight="45.0" prefWidth="55.0" text="−" textAlignment="CENTER" GridPane.columnIndex="3" GridPane.rowIndex="2">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="one" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press1" prefHeight="45.0" prefWidth="55.0" text="1" textAlignment="CENTER" GridPane.rowIndex="3">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="two" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press2" prefHeight="45.0" prefWidth="55.0" text="2" textAlignment="CENTER" GridPane.columnIndex="1" GridPane.rowIndex="3">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="three" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press3" prefHeight="45.0" prefWidth="55.0" text="3" textAlignment="CENTER" GridPane.columnIndex="2" GridPane.rowIndex="3">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="addBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#addPress" prefHeight="45.0" prefWidth="55.0" text="+" textAlignment="CENTER" GridPane.columnIndex="3" GridPane.rowIndex="3">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="zero" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#press0" prefHeight="45.0" prefWidth="112.0" text="0" textAlignment="CENTER" GridPane.halignment="LEFT" GridPane.rowIndex="4">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="decimalPnt" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#decPress" prefHeight="45.0" prefWidth="55.0" text="." textAlignment="CENTER" GridPane.columnIndex="2" GridPane.rowIndex="4">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
<Button fx:id="equalBttn" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#equalPress" prefHeight="45.0" prefWidth="55.0" text="=" textAlignment="CENTER" GridPane.columnIndex="3" GridPane.rowIndex="4">
<font>
<Font name="Verdana" size="16.0" />
</font>
</Button>
</children>
</GridPane>
<MenuBar layoutY="2.0" prefHeight="25.0" prefWidth="225.0">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Save equation to file" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Tools">
<items>
<MenuItem fx:id="binaryMI" mnemonicParsing="false" onAction="#binPressed" text="Convert to Binary" />
<MenuItem fx:id="hexMI" mnemonicParsing="false" onAction="#hexPressed" text="Convert to Hex" />
<MenuItem fx:id="formulaMI" mnemonicParsing="false" onAction="#formulaPressed" text="Enter Formula" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem fx:id="aboutPress" mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
<TextField fx:id="display" layoutY="80.0" maxWidth="-Infinity" minWidth="-Infinity" prefHeight="45.0" prefWidth="225.0" AnchorPane.topAnchor="25.0" />
</children>
</AnchorPane>
Controller for formula input:
public class FormulaInputFXMLController implements Initializable
{
@FXML
private TextField formulaField;
@FXML
private Button calcBttn;
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
@FXML
private void calcuatePressed(ActionEvent event) {
try{
FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("/simplecalculator/FXMLDocument.fxml"));
fxmlLoader.load();
FXMLDocumentController controller = fxmlLoader.getController();
controller.returnFormula(formulaField.getText());
Stage stage = (Stage)calcBttn.getScene().getWindow();
stage.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
Formula Input FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="75.0" prefWidth="350.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="simplecalculator.FormulaInputFXMLController">
<children>
<TitledPane animated="false" collapsible="false" focusTraversable="false" layoutX="74.0" layoutY="-65.0" prefHeight="75.0" prefWidth="350.0" text="Enter Formula Below:" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<HBox alignment="CENTER" layoutX="74.0" layoutY="-25.0" prefHeight="49.0" prefWidth="348.0" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TextField fx:id="formulaField" prefHeight="25.0" prefWidth="250.0" promptText="ex. 18+32 * (9 / 12)..." />
<Button fx:id="calcBttn" mnemonicParsing="false" onAction="#calcuatePressed" text="Calculate" />
</children>
</HBox>
</children>
</AnchorPane>
</content>
</TitledPane>
</children>
</AnchorPane>
Apologies if I've posted too much of the code, wasn't completely sure what info might not be relevant to the problem as a lot of my functions overlap.