-1

I want to bind the stage width and height together, so the user can only resize it by keeping the aspect ration.
This doesn't work:

stage.widthProperty().bind(stage.heightProperty());  

There is another way:

stage.minHeightProperty().bind(scene.widthProperty().multiply(1.3));  
stage.maxHeightProperty().bind(scene.widthProperty().multiply(1.3));  

But in this way I only set the width value.
How could I solve this?

Thanks,
Tibor

adxl
  • 829
  • 1
  • 9
  • 19
hazazs
  • 39
  • 1
  • 8
  • Have you used the search? https://stackoverflow.com/questions/16532962/how-to-make-javafx-scene-scene-resize-while-maintaining-an-aspect-ratio, https://stackoverflow.com/questions/41659245/how-to-preserve-image-ratio-and-resize-image-according-to-its-actual-size – Evgenij Reznik Mar 16 '20 at 15:19
  • Yeah, I have found these, but they don't contain the solution. The first simply doesn't work the way I want, and stage doesn't have fitWidthProperty and fitHeightProperty either. – hazazs Mar 16 '20 at 15:22

1 Answers1

2

Since the width and height properties are read-only you cannot bind them to anything, let alone each other. The reason they're read-only is documented:

Many of the Stage properties are read only because they can be changed externally by the underlying platform and therefore must not be bindable [because bound properties cannot be set].

Both the width and height properties have similar statements in their documentation.

You can still add a listener to each property and, when one property changes, set the other property to the new value. To make sure this doesn't lead to a StackOverflowError you'll have to track if you're currently setting the value in the listener. For example:

// not actually "binding" in the context of Property.bind(...)
public static void bindWidthAndHeightTogether(Window window, double widthToHeightRatio) {
  ChangeListener<Number> listener =
      new ChangeListener<>() {

        private boolean changing;

        @Override
        public void changed(ObservableValue<? extends Number> obs, Number ov, Number nv) {
          if (!changing) {
            changing = true;
            try {
              if (obs == window.widthProperty()) {
                window.setHeight(nv.doubleValue() / widthToHeightRatio);
              } else {
                window.setWidth(nv.doubleValue() * widthToHeightRatio);
              }
            } finally {
              changing = false;
            }
          }
        }
      };
  window.widthProperty().addListener(listener);
  window.heightProperty().addListener(listener);
}

The above worked for me on Windows 10 using JavaFX 14. Note that it prevents the window from being maximized properly but not from going full-screen (at least on Windows 10).

Slaw
  • 37,820
  • 8
  • 53
  • 80
  • The UX is pretty ugly if the user drags the corner of the window, for obvious reasons, but I don't really see any good way to work around that. I was working on something similar, with an additional `double widthToHeightRatio` parameter to the method. – James_D Mar 16 '20 at 17:09
  • 1
    I added a `widthToHeightRatio` parameter. I think I did it right (e.g. if the value is 1.5 then the width is 1.5 times the height). And yeah, unfortunately the window is choppy when resizing by dragging a corner. I think the only way to fix it is to remove the decorations and implement resize-by-drag manually. – Slaw Mar 16 '20 at 18:12