Skip to main content
Image

r/JavaFX


Size Behavior After Maximizing and Restoring Original Stage Size
Size Behavior After Maximizing and Restoring Original Stage Size

I am trying to create a JavaFX node. The node appears to work well, but I noticed that maximizing the stage causes it to grow large and then return to its correct size. This also happens when I click to go back to the original screen size. If I drag the stage's width and height, the node size behaves as expected. This behavior happens quickly, but is easier to see when returning to the original stage size. How do I calculate the sizes so that this behavior no longer happens?

  • Product Version: Apache NetBeans IDE 30

  • Java: 26.0.2; OpenJDK 64-Bit Server VM 26.0.2+10

  • Runtime: OpenJDK Runtime Environment 26.0.2+10

  • System: Windows 11 version 10.0 running on amd64; UTF-8; en_US (nb)

OverlapGraphView

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.SVGPath;

public class OverlapGraphView extends Region {

    // Style properties
    private final ObjectProperty<Paint> colorA = new SimpleObjectProperty<>(Color.web("#3B82F6", 0.2));
    private final ObjectProperty<Paint> strokeA = new SimpleObjectProperty<>(Color.web("#3B82F6"));
    
    private final ObjectProperty<Paint> colorBoth = new SimpleObjectProperty<>(Color.web("#8B5CF6", 0.4));
    private final ObjectProperty<Paint> strokeBoth = new SimpleObjectProperty<>(Color.web("#8B5CF6"));
    
    private final ObjectProperty<Paint> colorB = new SimpleObjectProperty<>(Color.web("#EC4899", 0.2));
    private final ObjectProperty<Paint> strokeB = new SimpleObjectProperty<>(Color.web("#EC4899"));

    // Exposed click event handlers
    private final ObjectProperty<EventHandler<? super MouseEvent>> onAOnlyClicked = new SimpleObjectProperty<>();
    private final ObjectProperty<EventHandler<? super MouseEvent>> onBothClicked = new SimpleObjectProperty<>();
    private final ObjectProperty<EventHandler<? super MouseEvent>> onBOnlyClicked = new SimpleObjectProperty<>();

    // Persistent shape views to prevent infinite layout recursion loops
    private final SVGPath pathAOnly = new SVGPath();
    private final SVGPath pathBoth = new SVGPath();
    private final SVGPath pathBOnly = new SVGPath();

    public OverlapGraphView() {
        setPrefSize(400, 200);

        // Bind presentation settings once in the constructor
        pathAOnly.fillProperty().bind(colorA);
        pathAOnly.strokeProperty().bind(strokeA);
        pathAOnly.setStrokeWidth(2);

        pathBoth.fillProperty().bind(colorBoth);
        pathBoth.strokeProperty().bind(strokeBoth);
        pathBoth.setStrokeWidth(3);

        pathBOnly.fillProperty().bind(colorB);
        pathBOnly.strokeProperty().bind(strokeB);
        pathBOnly.setStrokeWidth(2);

        setupHoverAnimation(pathAOnly);
        setupHoverAnimation(pathBoth);
        setupHoverAnimation(pathBOnly);

        // Map events directly onto persistent elements
        pathAOnly.setOnMouseClicked(e -> { if (onAOnlyClicked.get() != null) onAOnlyClicked.get().handle(e); });
        pathBoth.setOnMouseClicked(e -> { if (onBothClicked.get() != null) onBothClicked.get().handle(e); });
        pathBOnly.setOnMouseClicked(e -> { if (onBOnlyClicked.get() != null) onBOnlyClicked.get().handle(e); });

        // Add to child stack order once 
        getChildren().addAll(pathAOnly, pathBOnly, pathBoth);
    }

    /**
     * JavaFX calls this method safely during resize passes.
     * We modify properties of existing children rather than recreating nodes.
     */
    
    protected void layoutChildren() {
        super.layoutChildren();
        
        double w = getWidth();
        double h = getHeight();
        
        if (w <= 0 || h <= 0) return;

        // Calculate dynamic dimensions matching your scaling formula
        double radius = w * 0.23;
        double centerY = h * 0.5;
        double cxL = (w * 0.5) - (radius * 0.55);
        double cxR = (w * 0.5) + (radius * 0.55);

        // Calculate exact mathematical arc intersection points
        double dx = cxR - cxL;
        double d = Math.sqrt(dx * dx); 
        double a = (radius * radius - radius * radius + d * d) / (2 * d);
        double hPoint = Math.sqrt(radius * radius - a * a);
        double ix = cxL + a; 
        double iy1 = centerY - hPoint;
        double iy2 = centerY + hPoint;

        // Generate perfect SVG paths smoothly handling window maximums/restores
        String leftCrescent = String.format("M %f,%f A %f,%f 0 1,0 %f,%f A %f,%f 0 0,1 %f,%f Z", 
                ix, iy1, radius, radius, ix, iy2, radius, radius, ix, iy1);

        String centerLens = String.format("M %f,%f A %f,%f 0 0,1 %f,%f A %f,%f 0 0,1 %f,%f Z", 
                ix, iy1, radius, radius, ix, iy2, radius, radius, ix, iy1);

        String rightCrescent = String.format("M %f,%f A %f,%f 0 0,0 %f,%f A %f,%f 0 1,0 %f,%f Z", 
                ix, iy1, radius, radius, ix, iy2, radius, radius, ix, iy1);

        // Update backing rendering paths natively without clear/add cycles
        pathAOnly.setContent(leftCrescent);
        pathBoth.setContent(centerLens);
        pathBOnly.setContent(rightCrescent);
    }

    private void setupHoverAnimation(SVGPath shape) {
        shape.setOnMouseEntered(e -> shape.setOpacity(0.65));
        shape.setOnMouseExited(e -> shape.setOpacity(1.0));
    }

    public void setOnAOnlyClicked(EventHandler<? super MouseEvent> handler) { onAOnlyClicked.set(handler); }
    public void setOnBothClicked(EventHandler<? super MouseEvent> handler) { onBothClicked.set(handler); }
    public void setOnBOnlyClicked(EventHandler<? super MouseEvent> handler) { onBOnlyClicked.set(handler); }
}

Main

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class JavaFxTest extends Application {

    
    public void start(Stage primaryStage) {
        OverlapGraphView overlapGraphView = new OverlapGraphView();
        overlapGraphView.setOnAOnlyClicked(e -> {
            System.out.println("Filter table by: segment A!");
        });
        
        overlapGraphView.setOnBothClicked(e -> {
            System.out.println("Filter table by: segment Both!");
        });
        
        overlapGraphView.setOnBOnlyClicked(e -> {
            System.out.println("Filter table by: segment B!");
        });
        
        overlapGraphView.setMaxSize(200, 200);
        
        StackPane container = new StackPane(overlapGraphView);

        

        Scene scene = new Scene(container, 320, 200);
        primaryStage.setScene(scene);
        primaryStage.setTitle("UX Overlap Graph");
        primaryStage.show();
    }

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

Advertisement: Ditch the cozy games. Face dark mysteries, sudden jump scares, and non-stop adrenaline.
Ditch the cozy games. Face dark mysteries, sudden jump scares, and non-stop adrenaline.
Image Ditch the cozy games. Face dark mysteries, sudden jump scares, and non-stop adrenaline.


Kromium – A zero-bloat Chromium engine for Java applications
[deleted]
Kromium – A zero-bloat Chromium engine for Java applications

Hey everyone,

Embedding a reliable, modern web view in Java desktop apps usually means dealing with massive binaries, fragile JNI/JOGL dependencies, and clunky setups. To solve this, I just open-sourced Kromium (daviantegroup/kromium).

It is built from the ground up for the JVM. Whether you are using pure Java, or modern Kotlin/Compose, Kromium provides a seamless embedding experience.

Here are the main features:

* Tiny Installers (15–30MB): Instead of bundling massive Chromium binaries, Kromium automatically downloads and caches the native JCEF runtime on the user's first launch.

* Clean JS Bridge: Thread-safe JavaScript execution and Inter-Process Communication (with a Java-friendly API and Kotlin coroutine support).

* True Headless Mode: Perfect for Java-based backend scrapers, automation, or testing without pulling in heavy UI dependencies.

It's available under the Apache 2.0 license. I’d love for you to check out the repo, run the demo, and let me know what you think!

🔗 https://github.com/daviantegroup/kromium