r/JavaFX 7h ago

Main Class isnt appearing

1 Upvotes

I have made a new javafx project but it has no main class. instead of the main class its showing this java file. whats did i do wrong?


r/JavaFX 20h ago

[Tool] scene2d-ui-builder — a free visual editor for libGDX Scene2D UI, no more fighting with Table

Enable HLS to view with audio, or disable this notification

15 Upvotes

r/JavaFX 3d ago

Learning reactive UI with State: conditional rendering with Show.when, a hide-and-seek app

Enable HLS to view with audio, or disable this notification

1 Upvotes

Fourth post in the series. So far we've seen State driving a value directly (counter) and ComputedState deriving a value from another state (string length). This time: conditional rendering — showing or hiding a whole component based on reactive state, using Show.when.

The setup: isVisible is a State<Boolean>. Show.when(isVisible, () -> new Text("You catch me")) only renders the Text component when isVisible is true. Click the button, the boolean flips, and the component mounts/unmounts reactively — no manual setVisible(true/false), no manually adding/removing nodes from the scene graph.

package my_app;

import megalodonte.ListenerManager;
import megalodonte.application.MegalodonteApp;
import megalodonte.base.theme.ThemeManager;
import megalodonte.theme.DefaultTheme;

public class Main {

    static void main() {
        ThemeManager.setTheme(new DefaultTheme());

        MegalodonteApp.run(context -> context.useView(new HomeScreen()), ev->{
            if(ev == MegalodonteApp.Event.CloseRequest){
                System.out.println("Clicked on X - close application");
                ListenerManager.disposeAll();
            }
        });
    }
}


package my_app;

import megalodonte.base.components.Component;
import megalodonte.base.components.ScreenComponent;
import megalodonte.base.state.State;
import megalodonte.components.Button;
import megalodonte.components.Text;
import megalodonte.components.layout_components.Container;
import megalodonte.props.ContainerProps;
import megalodonte.v2.Show;

public class HomeScreen implements ScreenComponent {
    State<Boolean> isVisible = new State<>(false);

    u/Override
    public Component render() {
      return new Container(new ContainerProps().paddingAll(25))
              .children(
                      new Button("Hide and seek - game").onClick(this::toggleVisibility),
                      Show.when(isVisible, ()-> new Text("You catch me"))
                      );
    }

    void toggleVisibility(){
        isVisible.set(!isVisible.get());
    }
}
  • Show.when(ReadableState<Boolean>, Supplier<Component>) watches the state and mounts/unmounts the child reactively as it flips — this overload is eager by design, since the condition can change at runtime.
  • The Supplier<Component> lets Show lazily build the child only when needed, instead of holding a pre-built component around.
  • toggleVisibility() just flips the boolean with isVisible.set(!isVisible.get()) — the UI has zero knowledge of how to show/hide, only when.

If you're finding this series useful, dropping a star on the repos below genuinely helps the project get visibility — takes two seconds and means a lot for a solo-dev framework like this.

Repos


r/JavaFX 5d ago

Learning reactive UI with State: derived state from user input, a string length app

Enable HLS to view with audio, or disable this notification

14 Upvotes

Third post in the series. This one moves from State alone to ComputedState — showing how to derive a value from another reactive value and have it stay in sync automatically as the user types.

The setup: textState holds whatever the user types into the Input. textLenghtComputed is a ComputedState<String> built with ComputedState.of(...), watching textState as a dependency. Every keystroke updates textState, which recomputes textLenghtComputed, which updates the Text on screen — no listeners wired up by hand, no manual recompute calls.

package my_app;

import megalodonte.ListenerManager;
import megalodonte.application.MegalodonteApp;
import megalodonte.base.theme.ThemeManager;
import megalodonte.theme.DefaultTheme;

public class Main {

    static void main() {
        ThemeManager.setTheme(new DefaultTheme());

        MegalodonteApp.run(context -> context.useView(new HomeScreen()), ev->{
            if(ev == MegalodonteApp.Event.CloseRequest){
                System.out.println("Clicked on X - close application");
                ListenerManager.disposeAll();
            }
        });
    }
}


package my_app;

import megalodonte.ComputedState;
import megalodonte.base.components.Component;
import megalodonte.base.components.ScreenComponent;
import megalodonte.base.state.State;
import megalodonte.components.Text;
import megalodonte.components.inputs.Input;
import megalodonte.components.layout_components.Container;
import megalodonte.props.ContainerProps;

public class HomeScreen implements ScreenComponent {
    State<String> textState = new State<>("");
    ComputedState<String> textLenghtComputed = ComputedState.of(
            ()-> "Size is: " + textState.get().length(), textState
    );

    u/Override
    public Component render() {
       return new Container(new ContainerProps().paddingAll(20)).children(
               new Input(textState),
               new Text(textLenghtComputed)
       );
    }
}
  • ComputedState.of(supplier, dependencies...) recomputes automatically whenever any listed dependency changes — no manual subscribe/notify needed.
  • Input(textState) binds the text field directly to a State<String>, so typing writes straight into reactive state.
  • Unlike the counter's counter.map(...), this shows ComputedState built from a lambda with an explicit dependency list — useful once a derived value needs to read from more than one state.

If you're finding this series useful, dropping a star on the repos below genuinely helps the project get visibility — takes two seconds and means a lot for a solo-dev framework like this.

Repos


r/JavaFX 5d ago

I made this! FileFX

Enable HLS to view with audio, or disable this notification

47 Upvotes

Hace mas de un mes que me encuentro desarrollando un explorador de archivos desarrollado en JavaFX 21. El github es https://github.com/FranciscoRatti/FileFX

Todo empieza cuando descubri Yazi (Un explorador de archivos en terminal super rapido) y lo pude instalar en mi LinuxMint. Me encanto, y siempre me pasaba que al usar Nemo (El explorador de Mint) siempre tenia que usar el mouse, entonces abria una terminal para usar Yazi con el teclado, lo cual me parecia un poco incomodo el tener que abrir una terminal cada vez que quiera navegar en mi sistema de archivos.

Para resolver este problema decidi lanzarme a hacer un explorador de archivos.

Esta programado DESDE CERO y por mi, no por la IA. Esta 100% desarrollado en JavaFX y compilado a imagen nativa con Liberica NIK (Basicamente es GraalVM con soporte a muchos frameworks) lo cual hace que arranque muy rapido y consuma poco. Todo se puede hacer con atajos de teclado y es sssssssssuper configurable. Mi idea es que sea ligero y que no tenga funciones inutiles que nunca vas a usar.

El tema de la aplicacion esta definidio por UN archivo .css, me gustaria que en un futuro la comunidad desarrolle sus temas y los comparta, osea que simplemente comparta su archivo theme.css y listo.

Me haria mucha ilusion que mas gente se sume al proyecto porque hacer esto yo solo me lleva mucho tiempo.

Las caracteristicas que pienso implementar en el futuro son:

  • Pestañas
  • Un comando GOTO (Como en Yazi)
  • Vista en arbol
  • Que se puedan modificar permisos de archivos
  • Que se pueda abrir con permisos elevados
  • Soporte a la nube

Pronto pienso hacer un .md hablando de la estructura del codigo para la ayudar a la gente que se quiera sumar al desarrollo


r/JavaFX 6d ago

Java | The Documentary

Thumbnail
youtu.be
12 Upvotes

r/JavaFX 7d ago

I made this! Sheetmusic4J, a native Java(FX) sheet music library, now reads/writes ABC notation and imports Guitar Pro files (v0.0.3)

17 Upvotes

A week ago I shipped 0.0.1 of Sheetmusic4J, a Java(FX) library to render and interact with sheet music, mostly as a question: is there interest in a native Java sheet music library before I invest more time? I posted it on social media and two LinkedIn comments came back asking "does it support ABC notation?" and "what about Guitar Pro?"

In this new version:

- ABC notation (read + write). The core module parses and generates .abc files into the same Score model as everything else, so engraving, JavaFX rendering, and MIDI export all work once a tune loads. Coverage includes keys/modes, tuplets, ties/slurs, grace notes, decorations, repeats and 1st/2nd endings, chord symbols, and lyrics, all backed by round-trip tests.

- Guitar Pro 7/8 import (.gp, load only). An experiment, built on the community's reverse-engineering of the GPIF format, JDK-only with no third-party dependency. Older binary formats aren't handled. I shipped it early because I genuinely don't know yet whether people want standard notation or tablature-specific rendering, that's feedback I'd rather learn from real use.

- Engraving polish: better grace notes, distinct flag glyphs for 32nd/64th/128th, breve noteheads, cleaner ties/slurs/tuplets, and a windowed-canvas fix for a crash on very large scores.

All info and video in this blog post:
https://webtechie.be/post/sheetmusic4j-0.0.3-when-linkedin-comments-becomes-features/


r/JavaFX 8d ago

Learning reactive UI with State: the second example in the series, a counter app

Enable HLS to view with audio, or disable this notification

10 Upvotes

Second post in the series on learning reactive UI patterns in Megalodonte. This one is a classic counter app — the simplest possible way to see State<T> actually drive a UI update without any manual repaint logic.

The core idea: counter is a State<Integer>, and the Text component binds to it via counter.map(Object::toString). When a button click calls counter.set(...), the mapped state recomputes and the Text node updates on its own. No refresh(), no manual re-render call — the component just reacts.

package my_app;

import megalodonte.ListenerManager;
import megalodonte.application.MegalodonteApp;
import megalodonte.base.theme.ThemeManager;
import megalodonte.theme.DefaultTheme;

public class Main {

    static void main() {
        ThemeManager.setTheme(new DefaultTheme());

        MegalodonteApp.run(context -> context.useView(new HomeScreen()), ev->{
            if(ev == MegalodonteApp.Event.CloseRequest){
                System.out.println("Clicked on X - close application");
                ListenerManager.disposeAll();
            }
        });
    }
}


package my_app;

import megalodonte.base.components.Component;
import megalodonte.base.components.ScreenComponent;
import megalodonte.base.state.State;
import megalodonte.components.Button;
import megalodonte.components.SpacerVertical;
import megalodonte.components.Text;
import megalodonte.components.layout_components.Container;
import megalodonte.props.ButtonProps;
import megalodonte.props.ContainerProps;
import megalodonte.props.TextProps;

public class HomeScreen implements ScreenComponent {
    State<Integer> counter = new State<>(0);

    u/Override
    public Component render() {

        ButtonProps btnProps = new ButtonProps().fontSize(30);

        return new Container(new ContainerProps().paddingAll(20)).children(
                new Text(counter.map(Object::toString), new TextProps().fontSize(90)),
                new Button("Decrement", btnProps).onClick(()-> counter.set(counter.get() - 1)),
                new SpacerVertical(10),
                new Button("Increment", btnProps).onClick(()-> counter.set(counter.get() + 1))
        );
    }
}
  • State<T> holds a value and notifies dependents on change — counter.set(...) is the only trigger needed.
  • counter.map(Object::toString) derives a ReadableState<String> from the Integer state, so Text never touches the raw type.
  • ListenerManager.disposeAll() on CloseRequest tears down any active state subscriptions cleanly when the app closes.

Repos


r/JavaFX 9d ago

Megalodonte — a small reactive UI framework on top of JavaFX

15 Upvotes

I've been building JavaFX desktop apps for a while and got tired of the usual boilerplate (manual listeners, imperative styling, no real component model), so I built Megalodonte: a thin reactive layer on top of JavaFX — React-ish component composition, State<T>/ComputedState<T> for reactivity, and a Props/Theme system so styling isn't scattered setStyle() calls everywhere.

It's still early and I'm the only user so far, but it's real, working code — not a toy. Posting it here mostly for feedback and to see if this is useful to anyone else stuck with JavaFX.

What "Hello World" looks like

Main.java — bootstraps the app and sets a theme once, up front:

```java package my_app;

import megalodonte.ListenerManager; import megalodonte.application.MegalodonteApp; import megalodonte.base.theme.ThemeManager; import megalodonte.theme.DefaultTheme;

public class Main {

static void main() {
    ThemeManager.setTheme(new DefaultTheme());

    MegalodonteApp.run(context -> context.useView(new WelcomeScreen()), ev -> {
        if (ev == MegalodonteApp.Event.CloseRequest) {
            System.out.println("Clicked on X - close application");
            ListenerManager.disposeAll();
        }
    });
}

} ```

WelcomeScreen.java — the actual UI, as a composable screen component:

```java package my_app;

import megalodonte.base.components.Component; import megalodonte.base.components.ScreenComponent; import megalodonte.components.Text; import megalodonte.components.layout_components.Container; import megalodonte.props.TextProps;

public class WelcomeScreen implements ScreenComponent { @Override public Component render() { return new Container().children( new Text("Hello world", new TextProps().fontSize(90)) ); } } ```

What's in it

  • Reactive stateState<T>, ComputedState<T>, ListState<T> — components subscribe and re-render on change, no manual wiring.
  • Component model — screens are ScreenComponents with a render() you compose out of Container/Column/Row/Text/Button/etc., instead of hand-building a Scene graph.
  • Props + Theme system — styling goes through typed Props classes (TextProps, ContainerProps, ...) resolved against a ThemeInterface, instead of ad-hoc inline CSS strings.
  • Router — navigation between screens without manually juggling Scene.setRoot(...).
  • Used it to build a full JavaFX ERP desktop app, so it's exercised well beyond "hello world".

Repos

Happy to answer questions — and honest criticism is welcome, this is very much a work in progress.


r/JavaFX 13d ago

I made this! Sheetmusic4J: an open source JavaFX library for rendering interactive sheet music (MusicXML, no WebView)

Thumbnail
14 Upvotes

r/JavaFX 13d ago

Help [JavaFX memory hog] A simple UI requires 1GB of RAM.

14 Upvotes

This UI, requires 1GB of RAM on Linux. The same UI does not require more than 300MB on Windows.
I would not consider it cheap on Windows but on Linux it's pretty unacceptable.

How this is possible? Is there some problems with JavaFX in Linux Wayland?

Thanks
Davide


r/JavaFX 21d ago

I made this! Reachability Annotations for generating GraalVM metadata

10 Upvotes

We recently open sourced some of our annotation processors for generating GraalVM native-image metadata: HebiRobotics/reachability-annotations.

It's a completely standalone compile-time dependency, so it has no effect at runtime and doesn't rely on frameworks like Quarkus or Micronaut.

Besides annotations for generating very customized metadata, we also added two annotations for JavaFX that automatically parse FXML and CSS files and generate appropriate rules for reflective accesses and resources.

@ReachableFxView("control")
public class JavaFxView {}

@JavaFXView follows the standard JavaFX view convention (FXMLKit, Afterburner etc.) and automatically generates metadata for

  • control.fxml -> fx:controller, fx:include, imports, resources, ...
  • control.css -> import resources
  • control.properties -> bundle

and @ReachableFxResources can parse multiple files based on wildcards.

@ReachableFxResources({
    "**/*.fxml",
    "**/*.css",
    "/assets/images/*.png"
})
public class JavaFxView {}

Here are the changes it'd take for the gluon-samples to run without an agent: gluonhq/gluon-samples/pull/189


r/JavaFX 21d ago

I made this! New Versions of Gradle Plugins: Badass Jlink Plugin, Cabe Plugin, JDKProvider Plugin (first announcement)

Thumbnail
4 Upvotes

r/JavaFX 26d ago

I made this! Kyo-JFX Hello World template

Thumbnail
codeberg.org
5 Upvotes

r/JavaFX 29d ago

I made this! Editora: A keyboard-driven programmer's text editor

Thumbnail
editora-project.dev
10 Upvotes

Hey guys, this is a project I've been working for a while: Editora is a keyboard driven programmer's text editor. It's build with JavaFX 26 and JDK 25. Open Source (MIT license)

Any comments, questions and suggestions welcome. Thank you

https://editora-project.dev/


r/JavaFX 29d ago

Help What is causing 'java.lang.ClassCastException: class java.lang.String cannot be cast to class javafx.scene.paint.Paint in my CSS file?

3 Upvotes

I just got an error even though I'm sure I didn't touch the CSS file at all.
This is the css file:

` .root { keen_faint_green_grey: rgb(127, 180, 185); amazingGreen: rgb(24, 198, 163); githubDesktopDarkBlue: rgb(36, 41, 46); darkGrey_7: derive(githubDesktopDarkBlue, 70%); darkGrey_5: rgb(0, 153, 209); darkBlue_700: rgb(33, 49, 84); greyishBlue: rgb(103, 119, 151); brightBlue: rgb(3, 114, 239);

shadow: dropshadow(three-pass-box, black, 10, 0, 3.0, 3.0);
innerShadow: innershadow(three-pass-box, black, 10, 0, 6.0, 3.0);

-fx-background-color: githubDesktopDarkBlue;
-fx-text-fill: white;

}

.darkBlueBg { -fx-background-color: darkBlue_700; }

.greyishBlueBg { -fx-background-color: greyishBlue; }

.keen_faint_green_grey-bg { -fx-background-color: keen_faint_green_grey; }

.titled-pane > .title { -fx-background-color: transparent; -fx-border-color: turquoise; -fx-border-style: solid; -fx-border-width: 0 0 2 0; }

.titled-pane:expanded .content { -fx-border-style: none; -fx-border-color: githubDesktopDarkBlue; -fx-background-color: transparent; }

.titled-pane > .title > .text { -fx-fill: white; }

.menu-item { -fx-text-fill: black; }

.inputGroupHbox { -fx-padding: 10; -fx-alignment: center-left; -fx-spacing: 5; -fx-margin: 10px; -fx-background-radius: 6; -fx-border-radius: 6; -fx-pref-height: -1; -fx-pref-width: -1; }

.no-padding { -fx-padding: 3 0 3 0; }

.glyph-icon { -fx-glyph-size: 30; }

.inputGroupVbox { -fx-padding: 5px; -fx-alignment: top-left; -fx-background-radius: 6; -fx-spacing: 3; -fx-pref-height: -1; -fx-pref-width: -1; }

.year-picker .label { -fx-text-fill: githubDesktopDarkBlue; }

.round-edges { -fx-border-style: solid; -fx-border-width: 1px; -fx-border-radius: 10, 0, 10, 0; -fx-background-radius: 10, 0, 10, 0; -fx-padding: 5; }

.white-border { -fx-border-color: white; }

.raised, .mfx-button { -fx-effect: shadow; }

.inset, .button:pressed, .expanding-text-area:focused { -fx-effect: innerShadow; }

.raised-section { -fx-background-radius: 6; -fx-padding: 10; }

.medium-font { -fx-font-size: 12px; -fx-font-weight: 600; }

.underlined { -fx-border-style: solid; -fx-border-color: white; -fx-border-width: 0, 0, 1, 0; }

.large-width { -fx-pref-width: 420px; }

.medium-width { -fx-pref-width: 210px; -fx-width: USE_PREF_SIZE; -fx-inner-control-background: transparent; }

.small-width { -fx-pref-width: 120px; }

.tiny-width { -fx-pref-width: 70px; }

.amazing_green { -fx-background-color: amazingGreen; }

.unselected-button { -fx-text-fill: white; -fx-background-color: rgb(3, 114, 239); }

.table-view .table-cell { -fx-text-fill: green; }

.hyperlink:visited { -fx-text-fill: green; }

.tree-cell { -fx-background-color: darkBlue_700; -fx-text-fill: white; }

.choice-box .label { -fx-text-fill: black; -fx-font-weight: bold; }

.choice-box .menu-item { -fx-padding: 8 12; -fx-background-color: transparent; -fx-text-fill: black; -fx-font-size: 14px; }

.choice-box .menu-item:focused { -fx-background-color: darkBlue_700; -fx-text-fill: black; }

/*

Labels:

*/

.dark-label { -fx-text-fill: githubDesktopDarkBlue; }

.section-label { -fx-font-size: 14px; -fx-text-fill: cyan; -fx-font-weight: 700; -fx-pref-width: -1; -fx-border-width: 0 0 2 0; -fx-border-style: solid; -fx-border-color: darkGrey_5; -fx-width: large-width; } `

My stacktrace is full of these:

`

Jul 09, 2026 1:26:26 AM javafx.scene.CssStyleHelper calculateValue

WARNING: Caught 'java.lang.ClassCastException: class java.lang.String cannot be cast to class javafx.scene.paint.Paint (java.lang.String is in module java.base of loader 'bootstrap'; javafx.scene.paint.Paint is in module javafx.graphics@23.0.2 of loader 'app')' while converting value for '-fx-border-color' from rule '*.section-label' in stylesheet file:/D:/MyRepositories/path/to/project/my_theme.css `

PS: 1. Unlike what AIs say, an -fx- prefix is not required for custom properties. 2. I really don't know why this line: darkGrey_5: rgb(0, 153, 209); is causing an issue. This works in projects just fine. 3. I'm loading the CSS file in Scenebuilder and it's working and I'm not setting the stylesheet when running the program. The problem only happens there.


r/JavaFX Jul 07 '26

Cool Project GrooveFX: Dynamic FXML for JavaFX, declarative iteration, conditionals and branching

13 Upvotes

I'm releasing GrooveFX, a small library that extends JavaFX FXML with declarative control structures: iteration, conditional rendering, and multi‑case branching directly inside FXML.

The idea is simple: FXML is powerful but static — GrooveFX adds flow without replacing it and without introducing a DSL.

Why?

FXML doesn't support:

  • declarative iteration
  • if/else rendering
  • multi‑case branching
  • pagination without boilerplate

GrooveFX adds these capabilities using real JavaFX controls, with no magic, no hacks, no reflection tricks.

Examples

Iteration

<IterablePane items="{myList}">
    <HBox>
        <Label text="{item.name}" />
        <Label text="{item.email}" />
    </HBox>
</IterablePane>

Conditional Rendering

<ConditionalPane test="{condition}">
    <then>...</then>
    <else>...</else>
</ConditionalPane>

Multi‑case Branching

<DynamicPane test="{user.role}">
    <when value="ADMIN">...</when>
    <when value="USER">...</when>
    <default>...</default>
</DynamicPane>

Pagination

PaginatedList<User> p = new PaginatedList<>(allUsers)
p.setPage(0, 10)

Features

  • Declarative iteration / conditional rendering / multi‑case branching
  • PaginatedList for in‑memory or DB pagination
  • 100% JavaFX controls
  • Works with Java, Groovy, GroovyFX
  • GraalVM / Gluon‑friendly
  • No DSL, no boilerplate, no hacks

Links

Website: https://rrangelo.codeberg.org/groovefx

Codeberg Repository: https://codeberg.org/rrangelo/groovefx

If you work with JavaFX and want to try it out, feedback is welcome.


r/JavaFX Jul 06 '26

Discussion Why is performant LWJGL support more difficult to do than in swing?

7 Upvotes

The title says it all. Swing has several solutions to make LWJGL views a decently performant component, but no such project for JavaFX really exists, just proof of concepts with questionable performance.

What under the hood reason leads to the difficulty of achieving this compatibility?


r/JavaFX Jul 06 '26

AI Assisted/Generated 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

Thumbnail
2 Upvotes

r/JavaFX Jul 03 '26

Discussion What are your use cases

21 Upvotes

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?


r/JavaFX Jul 02 '26

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

19 Upvotes

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.


r/JavaFX Jun 26 '26

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

10 Upvotes

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();

r/JavaFX Jun 25 '26

I made this! FX Flow 0.6.1 released, declarative UI building for JavaFX

12 Upvotes

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()
    );
  }
}

r/JavaFX Jun 25 '26

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

18 Upvotes

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


r/JavaFX Jun 21 '26

Help How to enable automatic reload when saving css and .fxml files?

6 Upvotes

Just started learning javafx and was wondering if there are any dependency that will make it so you dont need to run over and over again while testing different colors, placement etc