JavaFx USE_COMPUTED_SIZE for Stage without using FXML
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.
Zelphir Kaltstahl
Updated on June 23, 2022Comments
-
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
orContainer
. There are predefined values likeUSE_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:
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 about 9 yearsIt 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."
-
Zelphir Kaltstahl about 9 yearsI 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 about 9 yearsSurely you can create (from scratch) a complete, executable example that does the same thing but involves only a few lines of code?
-
Zelphir Kaltstahl about 9 yearsActually 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 about 9 yearsEDIT2: Smaller example with different result added.
-
ItachiUchiha about 9 yearsThe culprit is
GridPane.setRowSpan(tex, 2);
. Try removing it. -
Zelphir Kaltstahl about 9 yearsThat 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 : )
-