Search code examples
javajavafxjavafx-bindings

JavaFX: Bind SimpleLongProperty to a Label and format long value to human readable filesize


I have a Label which is binded to two Properties. The first value (deletedFilesCountProperty) is a simple int without needing for formatting. But how can I format the second property (SimpleLongProperty) to a human readable filesize value?

Example: deletedFilesSize's value is 1000000. The label should show "1MB" instead.

Can I call the humanReadableByteCount function inside the Binding to let this function format the value?

My code so far:

public class MainController implements Initializable {
    private final SimpleIntegerProperty deletedFilesCount = new SimpleIntegerProperty();
    private final SimpleLongProperty deletedFilesSize = new SimpleLongProperty();

    @FXML
    Label deletedFilesLabel;


    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        deletedFilesLabel.textProperty().bind(Bindings.format("Deleted files: %d (%d)", deletedFilesCountProperty(), deletedFilesSizeProperty()));
    }

    /**
    * formats a long number to a human readable file size value
    * returns something like: 2MB or 4GB and so on instead of very long Long values.
    */
    public static String humanReadableByteCount(long bytes, boolean si) {
        int unit = si ? 1000 : 1024;
        if (bytes < unit)
            return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(unit));
        String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
        return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
    }
}

Thanks.


Solution

  • Use Bindings.createStringBinding(...). A simple example would look like:

    fileSizeLabel.bind(Bindings.createStringBinding(
        () -> humanReadableByteCount(deletedFilesSizeProperty().get(), false),
        deletedFilesSizeProperty()
    ));
    

    Your specific example would look something like:

    deletedFilesLabel.textProperty().bind(Bindings.createStringBinding(
        () -> String.format(
            "Deleted files: %d (%s)",
            deletedFilesCountProperty().get(), 
            humanReadableByteCount(deletedFilesSizeProperty().get(), false)
        ),
        deletedFilesCountProperty(),
        deletedFilesSizeProperty()
    ));