'Investment value calculator

This is supposed to be an investment value calculator using JavaFX, and I got most of the code working. I just can't get it to properly show the future value amount. Despite calling tfFutureValue.setText, I do not see the expected value in the field. It remains blank.

Simply compile and run the program, enter numbers in the editable fields and click the "Calculate" button. The expected result is that the future value is displayed in the non-editable field as a calculation result. But the field still looks blank, despite me setting a text value.

Any help would be appreciated, I've been at it for a while can't seem to understand what is wrong.

public class InvestCalc extends Application {
    
    private TextField tfInvestmentAmount = new TextField();
    private TextField tfNumYears = new TextField();
    private TextField tfAnnualIntRate = new TextField();
    private TextField tfFutureValue = new TextField();
    private Button btCalculate = new Button("Calculate");
    
    @Override
    public void start(Stage primaryStage) {
        
        GridPane gridPane = new GridPane();
        gridPane.setHgap(5);
        gridPane.setVgap(5);
        gridPane.add(new Label("Investment Amount: "), 0, 0);
        gridPane.add(tfInvestmentAmount, 1, 0);
        gridPane.add(new Label("Number of Years: "), 0, 1);
        gridPane.add(tfNumYears, 1, 1);
        gridPane.add(new Label("Annual Intrest Rate: "), 0, 2);
        gridPane.add(tfAnnualIntRate, 1, 2);
        gridPane.add(new Label("Future Value: "), 0, 3);
        gridPane.add(tfFutureValue, 1, 3);
        gridPane.add(btCalculate, 1, 4);
        
        gridPane.setAlignment(Pos.BASELINE_CENTER);
        tfInvestmentAmount.setAlignment(Pos.BOTTOM_RIGHT);
        tfNumYears.setAlignment(Pos.BOTTOM_RIGHT);
        tfAnnualIntRate.setAlignment(Pos.BOTTOM_RIGHT);
        tfFutureValue.setAlignment(Pos.BOTTOM_RIGHT);
        tfFutureValue.setEditable(false);
        GridPane.setHalignment(btCalculate, HPos.RIGHT);
        
        btCalculate.setOnAction(e -> calculateInvestment());
        
        Scene scene = new Scene(gridPane, 400, 250);
        primaryStage.setTitle("Investment Calculator");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private void calculateInvestment() {
        double annualIntrest = Double.parseDouble(tfAnnualIntRate.getText());
        int numYears = Integer.parseInt(tfNumYears.getText());
        double investAmount = Double.parseDouble(tfInvestmentAmount.getText());
        
        double value = investAmount * Math.pow(1 + annualIntrest, numYears *12);
        
        tfFutureValue.setText("$%.2f" + value);
    }
    
    public static void main(String[] args) {
        launch(args);
    }

}


Solution 1:[1]

Here is an MCVE for a working version:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>SO_Java_JavaFxRefreshFieldValue_71812697</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-maven-plugin</artifactId>
        <version>0.0.8</version>
        <configuration>
          <mainClass>InvestCalc</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.openjfx</groupId>
      <artifactId>javafx-controls</artifactId>
      <version>17.0.1</version>
    </dependency>
  </dependencies>

</project>
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

/**
 * Run via 'mvn javafx:run'
 */
public class InvestCalc extends Application {
  private TextField tfInvestmentAmount = new TextField();
  private TextField tfNumYears = new TextField();
  private TextField tfAnnualIntRate = new TextField();
  private TextField tfFutureValue = new TextField();
  private Button btCalculate = new Button("Calculate");

  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    GridPane gridPane = new GridPane();
    gridPane.setHgap(5);
    gridPane.setVgap(5);
    gridPane.add(new Label("Investment Amount: "), 0, 0);
    gridPane.add(tfInvestmentAmount, 1, 0);
    gridPane.add(new Label("Number of Years: "), 0, 1);
    gridPane.add(tfNumYears, 1, 1);
    gridPane.add(new Label("Annual Interest Rate [%]: "), 0, 2);
    gridPane.add(tfAnnualIntRate, 1, 2);
    gridPane.add(new Label("Future Value: "), 0, 3);
    gridPane.add(tfFutureValue, 1, 3);
    gridPane.add(btCalculate, 1, 4);
    gridPane.setAlignment(Pos.BASELINE_CENTER);

    tfInvestmentAmount.setAlignment(Pos.BOTTOM_RIGHT);
    tfNumYears.setAlignment(Pos.BOTTOM_RIGHT);
    tfAnnualIntRate.setAlignment(Pos.BOTTOM_RIGHT);
    tfFutureValue.setAlignment(Pos.BOTTOM_RIGHT);
    tfFutureValue.setEditable(false);
    GridPane.setHalignment(btCalculate, HPos.RIGHT);

    Scene scene = new Scene(gridPane, 400, 250);

    btCalculate.setOnAction(e -> calculateInvestment());

    primaryStage.setTitle("Investment Calculator");
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  private void calculateInvestment() {
    double annualInterest = Double.parseDouble(tfAnnualIntRate.getText());
    int numYears = Integer.parseInt(tfNumYears.getText());
    double investAmount = Double.parseDouble(tfInvestmentAmount.getText());
    double value = investAmount * Math.pow(1 + annualInterest * 0.01, numYears);
    tfFutureValue.setText(String.format("%.2f", value));
  }
}

Now run the program with mvn javafx:run. Let's find out the future value for an investment of 1000 for 2 years with 3% interest:

screenshot

That looks correct. So what was wrong?

The main problem was this line which tries to concatenate a format string and a double value:

tfFutureValue.setText("$%.2f" + value);

The correct version is:

tfFutureValue.setText(String.format("%.2f", value));

I also suggest to tell the user to enter the interest as a percent value rather than a floating point number between 0 and 1, because this is what most people expect:

gridPane.add(new Label("Annual Interest Rate [%]: "), 0, 2);

And then divide by 100 in the formula. Also fix the bug that we are asking for a number of years but the original code was trying to calculate based on months:

double value = investAmount * Math.pow(1 + annualInterest * 0.01, numYears);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 kriegaex