JavaFx USE_COMPUTED_SIZE for Stage without using FXML

12,815

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.

Share:
12,815
Zelphir Kaltstahl
Author by

Zelphir Kaltstahl

Updated on June 23, 2022

Comments

  • Zelphir Kaltstahl
    Zelphir Kaltstahl almost 2 years

    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);
        }
    }
    
    • jewelsea
      jewelsea about 9 years
    • Zelphir Kaltstahl
      Zelphir Kaltstahl about 9 years
      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 : /
    • James_D
      James_D about 9 years
      Surely you can create (from scratch) a complete, executable example that does the same thing but involves only a few lines of code?
    • Zelphir Kaltstahl
      Zelphir Kaltstahl about 9 years
      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.
    • Zelphir Kaltstahl
      Zelphir Kaltstahl about 9 years
      EDIT2: Smaller example with different result added.
    • ItachiUchiha
      ItachiUchiha about 9 years
      The culprit is GridPane.setRowSpan(tex, 2);. Try removing it.
    • Zelphir Kaltstahl
      Zelphir Kaltstahl about 9 years
      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 : )