JavaFx USE_COMPUTED_SIZE for Stage without using FXML
Asked Answered
I

2

7

In the JavaFX Scene Builder, I can select a value for the minimum, maximum and preferred width and height of a Control or Container. There are predefined values like USE_COMPUTED_SIZE.

I came to the conclusion, that I don't like to use FXML for my current project, for several reasons and now I am wondering how to set those values when not using FXML.

How do I do this?

I've tried the following code:

initializeControls();
addControls();


setMinHeight(Control.USE_COMPUTED_SIZE);
setMinWidth(Control.USE_COMPUTED_SIZE);

addActionListeners();
addFocusChangeListeners();

However, that results in an Exception when trying to create the Stage:

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: The width and height must be >= 0. Got: width=-1; height=-1
at com.sun.glass.ui.Window.setMinimumSize(Window.java:984)
at com.sun.javafx.tk.quantum.WindowStage.setMinimumSize(WindowStage.java:291)
at javafx.stage.Stage.impl_visibleChanging(Stage.java:1154)
at javafx.stage.Window$9.invalidated(Window.java:743)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:143)
at javafx.stage.Window.setShowing(Window.java:841)
at javafx.stage.Window.show(Window.java:856)
at javafx.stage.Stage.show(Stage.java:255)
at dictionary.MainApp.trainVocablesButtonActionPerformed(MainApp.java:281)
at dictionary.MainApp.lambda$addActionListeners$2(MainApp.java:240)
at dictionary.MainApp$$Lambda$281/81350454.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8216)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3724)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3452)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1728)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2461)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:348)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:273)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:382)
at com.sun.glass.ui.View.handleMouseEvent(View.java:553)
at com.sun.glass.ui.View.notifyMouse(View.java:925)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$45(GtkApplication.java:126)
at com.sun.glass.ui.gtk.GtkApplication$$Lambda$42/379110473.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)

I guess, that I took the USE_COMPUTED_SIZE value from the wrong class or something, but where do I get the correct value from? Or is this whole approach somehow wrong?

My ultimate goal is to make the stage take as much space as is needed to display all the controls and containers in it, but not more.

EDIT#1: Correction: It should take as much space as needed as a Minimum width and height, so that the window is still resizeable but cannot be made so small that controls are not displayed any more.

EDIT#2: Result of trying to set the minimum width + height on a smaller example app: enter image description here

Code:

package javafxapplication3;

import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.paint.RadialGradientBuilder;
import javafx.scene.paint.Stop;
import javafx.stage.Stage;

public class GridPaneExample extends Application {
private final Paint background = RadialGradientBuilder.create()
            .stops(new Stop(0d, Color.TURQUOISE), new Stop(1, Color.web("3A5998")))
            .centerX(0.5d).centerY(0.5d).build();
    @Override
    public void start(Stage primaryStage) {
        GridPane root = new GridPane();
        root.setPadding(new Insets(5));
        root.setHgap(2);
        root.setVgap(2);
        root.setAlignment(Pos.CENTER);
        final TextField tex = new TextField();
        tex.setPrefWidth(250);
        tex.setPrefHeight(50);
        tex.setPromptText("Press the buttons to Display text here");
        tex.setFocusTraversable(false);
        GridPane.setColumnSpan(tex, 7);
        GridPane.setRowSpan(tex, 2);
        root.add(tex, 0, 0);
        GridPane.setHalignment(tex, HPos.CENTER);
        final Button[][] btn = new Button[5][5];
        char ch = 'A';
        for ( int i = 0; i < btn.length; i++) {
            for ( int j = 0; j < btn.length; j++) {

                btn[i][j] = new Button("" + ch);
                btn[i][j].setPrefSize(50, 50);
                root.add(btn[i][j], j, i+2);
                ch++;
                btn[i][j].setOnMouseClicked((mouseEvent) -> {
                    Button b = (Button) mouseEvent.getSource();
                    tex.appendText(b.getText());
                });
            }
        }

        Scene scene = new Scene(root,background);

        primaryStage.setTitle("Grid Pane Example");


        primaryStage.setScene(scene);

        primaryStage.setWidth(Control.USE_COMPUTED_SIZE);
        primaryStage.setHeight(Control.USE_COMPUTED_SIZE);

        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}
Innuendo answered 18/2, 2015 at 0:15 Comment(7)
It is usually best to supply real executable code that replicates the stack trace you provide. Also note: "If no size is specified, the scene will automatically compute its initial size based on the preferred size of its content."Somersault
I understand, but it is this computed value, which I want to have as a minimum value for width and for height, so that the window can become bigger but not smaller than the computed size. About the code: It's really pages of code for that stage, is it really appropriate to put so much in here? Also I'd have to make it executable on it's own first, since it is not the main window of my application, or even more code, post the whole application. I think there should be a standard way how to achieve the desired effect, no matter what the stage is for. I just can't figure that one out : /Innuendo
Surely you can create (from scratch) a complete, executable example that does the same thing but involves only a few lines of code?Ashburn
Actually this is difficult. "From scratch" doesn't result in the same exception for some reason I don't know and if it did the "same", it would not only involve a few lines of code, since "the same" is quite a lot. However something different happens with another smaller example application, that I tried to do this with: The minSize is ignored / has the wrong value. I can still make the window smaller than the space needed. Isn't there a general way how to get this effect? That's the main question here.Innuendo
EDIT2: Smaller example with different result added.Innuendo
The culprit is GridPane.setRowSpan(tex, 2);. Try removing it.Methodize
That didn't change anything, except how it looks. The window is still resizeable to sizes lower than the needed amount of space. You also could've posted this as an answer : )Innuendo
I
0

One of the comments helped me to find a solution, although it might not be the best solution: After adding all controls to the scene I simply can do the following:

setMinWidth(getWidth());
setMinHeight(getHeight());

This works because JavaFX initially sets the stage to a size needed by the controls on its scene.

Innuendo answered 19/2, 2015 at 20:17 Comment(0)
W
0

Probably late to the party but here is what I found out:

For Textfield there is a static field TextField.USE_COMPUTED_SIZE which has the value -1

I assume you can pass -1 to the Stage as well.

Wauters answered 5/7, 2020 at 0:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.