r/JavaFX

▲ 2 r/JavaFX+1 crossposts

Made a free keyboard-driven photo culling tool because I couldn't find similar one that justify paying for — would love feedback from people who actually cull a lot

I had ~70k photos backed up across trips and phone dumps and no sane way to sort them. Every culling tool I found was either paid or missing the one thing I actually wanted: full-screen photo, press a key, it's filed, next photo loads instantly. No drag-and-drop, no catalog import, no lag.

So I built ImageSorterPro — a JavaFX desktop app where you press 1/2/e/Delete/etc. to route a photo into a folder, hands never leaving the keyboard.

The part I'm actually proud of is the caching: an access-order LRU (abusing LinkedHashMap's access-order mode for free eviction), a sliding pre-cache window that leans forward (20 behind, 30 ahead, since you cull forward way more than you scrub back), a priority thread pool so anything you explicitly request jumps the queue ahead of background pre-caching, and aggressive cancellation of in-flight decodes that fall outside your current window once you jump around. End result: the next photo is basically always already decoded before you ask for it.

I wrote up the full breakdown (with code) here: Article

Repo: https://github.com/nirmal-mewada/ImageSorterPro

Yes, it has rough edges — no HEIC support yet, video backend has been a genuine nightmare (RIP several VLCJ integration attempts), GraalVM native-image only cooperates on Windows. I know JavaFX is not the trendy choice in 2026 and I've got a Rust/Tauri rewrite spec sitting in the repo, but the boring stack shipped and the trendy one didn't, so here we are.

Love yo here feedback and any contributions are most welcome !!

Edit: For those who are suggesting other tools, please consider my points on post about cost, efficiency and speed of doing this. Again this is not to replace any of such tools, but to do only one job, very efficiently - photo culling and free.

reddit.com
u/Active_Ad_4026 — 22 hours ago
▲ 20 r/JavaFX

What are your use cases

I have always had a passion for JavaFX but the usecase scenarios never seem to surface for anything more then personal apps I use to improve my personal workload management, occasionally some small team specific use cases. I have never found anything at the enterprise level that didnt have a better solution.

Can anyone share whaere they have found this to be the clear winner for an enterprise solution and why?

reddit.com
u/Uaint1stUlast — 4 days ago
▲ 20 r/JavaFX+1 crossposts

Closing the visual gap between Lottie4J and the official Lottie web player with frame-by-frame diff testing + rendering fixes

I've been working on Lottie4J, a JavaFX library to play Lottie animations, and one persistent problem was that some animations looked noticeably different from the official web player, even when no exceptions were thrown, and the code seemed fine.

This post covers the work I did to actually measure and close that gap:

New comparison workflow

The old approach used a JavaFX WebView running lottie-web as a reference, which it turns out doesn't fully support the latest player. I switched to dotlottie-wc (thorvg), the engine LottieFiles is now standardizing on, rendered via a headless Chrome instance. Reference images are committed to the repo and each test run diffs every frame of the JavaFX output against them. This runs headless on GitHub Actions using JavaFX 26's new headless rendering support.

Rendering fixes

With concrete diffs to work from, the problem areas became obvious:

  • Gradients: alpha/colour stops merged at union offsets, linear-RGB stops densified
  • Mattes: inverted-alpha matte type (tt: 2) now handled correctly
  • Easing: ported lottie-web's BezierEaser, added bisection fallback for flat-point curves
  • Blur, blend modes, text colour — all improved

Most animations now hit 99.5%+ similarity. The toughest file is still at 95.2%.

Full write-up: https://webtechie.be/post/closing-the-visual-gap-between-the-official-lottie-webplayer-and-lottie4j/

GitHub: https://github.com/lottie4j/lottie4j

If you have a Lottie animation that renders differently than you'd expect in JavaFX, I'd love to hear about it. Please, open an issue with the JSON and the differences you have seen between expected and JavaFX rendered.

u/FrankCodeWriter — 5 days ago
▲ 9 r/JavaFX

Thoughts on the Drag / Drop API / thoughts on a builder based approach?

So what are folk's opinions on the Drag and Drop API for JavaFX? I wasn't the biggest fan of having loads of separate methods that can be called separately. So I did a small proof of concept of a builder-like way of doing the drag and drop logic to see what it would look like and, tbh, I quite like it.

Am I in a minority here, or would there be some potential in fleshing out a builder-based way to do it?

        Label draggable = new Label("Drag Me!");
        ObservableList<String> items = FXCollections.observableArrayList();
        ListView<String> dropTarget = new ListView<>(items);

        Drag.enable(draggable)
                .payload("Drag Payload is doing stuff yay!")
                .onStart(context -> System.out.println("Drag Started on payload!"))
                .onEnd(context -> System.out.println("Drag ended with mode: " + context.getTransferMode()))
                .init();

        Drop.enable(dropTarget)
                .onDrop(context -> items.add(context.getPayload().toString()))
                .init();
reddit.com
u/Fuzzy-System8568 — 10 days ago
▲ 12 r/JavaFX

FX Flow 0.6.1 released, declarative UI building for JavaFX

I've released FX Flow 0.6.1, a JavaFX utility library focused on declarative UI construction, and reducing boilerplate around models, validation and reactive UI updates. See the end of this post for a full example.

Some highlights since the 0.5 release:

Validation feedback directly from domains

Domains can now contain Rules, which is a predicate associated with a Template explaining why a value is invalid. All built-in domain factory methods now provide validation messages. Domains can provide templates for out of range values, misaligned values, missing values, non matching values (regex), etc.

Together with the new ValidationEvent, AbstractMarkerPane and ValidationMarkerPane, validation feedback can be surfaced in the UI without wiring validation logic directly into controls. See the ValidationSampleApplication.

Coordinated observable updates

A new UpdatableValue type allows multiple values to be updated atomically, ensuring listeners never observe intermediate state because the listeners of the individual properties are only fired until all values have been updated:

// Create two updatable values (similar to properties):
UpdatableValue<String> firstName = UpdatableValue.of("Jane");
UpdatableValue<String> lastName = UpdatableValue.of("Smith");

// Observe them:
Observe.values(firstName, lastName)
    .subscribe((fn, ln) -> System.out.println(fn + " " + ln));  // prints "Jane Smith"

// Modify both properties at once:
UpdatableValue.set(
    firstName, "John",
    lastName, "Doe"
);

In this example, it will initially print Jane Smith followed by John Doe. The subscriber only sees the final (John, Doe) state. If you put a direct ChangeListener on one of these properties (and then use get to read the value of the other) you will not observe a temporary incorrect combination either (so you will never see Jane Doe or John Smith).

The advantage of using Observe.subscribe with multiple values is convenience, and that you also get notified if only one of the values changed (ie. from John Doe to John Miller) without having to manually monitor both properties.

Feedback and suggestions are welcome.

GitHub: https://github.com/int4-org/FX/releases

Full example:

public class ValidationSampleApplication extends Application {

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

  @Override
  public void start(Stage primaryStage) {
    StringModel name = StringModel.of(Domain.regex("[A-Z][a-z]+", Template.of("custom.startsWithCapital")));
    IntegerModel age = IntegerModel.of(null, Domain.bounded(18, 120));

    /*
     * Create a scene with a ValidationMarkerPane as the root. Markers will be overlaid
     * on the controls within the pane:
     */

    Scene scene = Scenes.create(
      ValidationMarkerPane.of().onMarkerCreated(this::installTooltip).content(
        Panes.vbox("form").nodes(
          Panes.grid("grid")
            .row("Name", FX.textField().promptText("Name (e.g. John)").model(name))
            .row("Age", FX.textField().promptText("Age (18-120)").model(age)),
          FX.button().text("Submit")
            .enable(Observe.booleans(name.valid(), age.valid()).allTrue())
        )
      )
    );

    /*
     * Add some basic styling.
     */

    scene.getStylesheets().add(StyleSheets.inline(
      """
      .form {
        -fx-padding: 2em;
        -fx-spacing: 1.5em;
        -fx-alignment: top-center;
      }
      .grid {
        -fx-hgap: 1em;
        -fx-vgap: 1em;
      }
      """
    ));

    primaryStage.setScene(scene);
    primaryStage.setTitle("Validation Marker Sample");
    primaryStage.sizeToScene();
    primaryStage.show();
  }

  private void installTooltip(Marker marker) {
    marker.validationIssueProperty().subscribe(issue -> {
      Tooltip tooltip = marker.getTooltip();

      if(tooltip == null) {
        tooltip = new Tooltip();

        marker.setTooltip(tooltip);
      }

      tooltip.setText(switch(issue) {
        case ValidationIssue.Invalid(Object _, Template template) -> toMessage(template);
        case ValidationIssue.Incompatible(Template template) -> toMessage(template);
      });
    });
  }

  static String toMessage(Template template) {
    return MessageFormat.format(
      switch(template.key()) {
        case "domain.missing" -> "Must not be empty";
        case "domain.invalid" -> "Must be a valid value";
        case "domain.notContained" -> "Must be one of {0}";
        case "domain.noMatch" -> "Must match regular expression {0}";
        case "domain.outOfRange" -> "Must be between {0} and {1}";
        case "domain.misaligned" -> "Must be a multiple of {1} starting from {0}";
        case "conversion.incompatible" -> "Must be a compatible value";
        case "custom.startsWithCapital" -> "Must consist of two or more letters and start with a capital";
        default -> "Invalid (" + template.key() + ")";
      },
      template.args().values().toArray()
    );
  }
}
u/john16384 — 12 days ago
▲ 18 r/JavaFX+1 crossposts

JMathAnim: a JavaFX library and UI to create mathematical animations (interview with the creator)

I interviewed David Gutierrez, a Spanish mathematician who built JMathAnim during the COVID lockdowns. He's not a trained developer, which makes this project even more interesting. He needed a tool that didn't exist in Java, knew Java well enough, and just... built it.

JMathAnim is inspired by Manim (the Python library behind a lot of 3Blue1Brown-style content) and lets you create animated math visualizations entirely in code. You can animate LaTeX formulas morphing step by step, build geometric visualizations, generate fractals, simulate cell growth, and export everything directly to video. No intermediate steps.

Under the hood, it uses a JavaFX Canvas for rendering, JLatexMath for the LaTeX side, and JavaCV for video export. There's also a built-in code editor with syntax highlighting via RSyntaxTextArea, which makes it accessible without needing a full IDE setup.

One design choice that surprised me: the interactive editor uses Ruby as the scripting language, not Java. Practical decision, it fits well with the short expressive scripts you write to define animation sequences.

David's own admission is that JavaFX had a learning curve for him. But the result speaks for itself. The base-10 to base-5 conversion example in the video is a good demo of what this kind of tool can do for education.

Video + write-up: https://webtechie.be/post/javafx-in-action-%2327-with-david-gutierrez-about-jmathanim-to-create-mathematical-animations/

Source code is on Codeberg: https://codeberg.org/davidgutierrezrubio/jmathanim

u/FrankCodeWriter — 12 days ago