user2329125
user2329125

Reputation:

How do I make a Vbox use the entire space

This is javafx8, I have to write that here since i do not have enough rep to use the tag.

Simple example:

public class Test extends Application
{
  public static void main(String args[]) throws Exception { launch(args); }

  private Canvas canvas;

  @Override
  public void start(Stage primaryStage)
  {
    VBox box = new VBox();

    Button dummyButton = new Button("some text");
    canvas = new Canvas();
    canvas.heightProperty().addListener(observable -> draw());
    canvas.widthProperty().addListener(observable -> draw());

    VBox.setVgrow(canvas, Priority.ALWAYS);

    box.getChildren().addAll(dummyButton, canvas);

    Scene scene = new Scene(box, 1300, 800);
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  private void draw()
  {
    final double width = canvas.getWidth();
    final double height = canvas.getHeight();
    System.out.println("w, h: " + width + "; " + height);
    final GraphicsContext gc = canvas.getGraphicsContext2D();
    gc.setFill(Color.GREENYELLOW);
    gc.fillRect(0, 0, width, height);
  }
}

I probably misread the documentation of vbox, at the bottom it says that

For example, if a vbox needs the ListView to be allocated all extra space

and then does this VBox.grow thing, just as I did in my example. But the canvas is never changing his size. It always has a width and height of 0, while I expected the canvas to grow and shrink as I resize the window.

How can I get my canvas ( and I guess with that also my vbox ) to use the entire vertical space available.

Please do not suggest the use of the primary stage, in my real application I am so many layers away from that with many other elements in between. Primary stage is only here to have a runnable program.

Upvotes: 0

Views: 880

Answers (1)

Michael Lampe
Michael Lampe

Reputation: 674

Your draw method is a bit messed up.

private void draw() {
  final double width = canvas.getWidth();
  final double height = canvas.getHeight();
  System.out.println("w, h: " + width + "; " + height);
  final GraphicsContext gc = canvas.getGraphicsContext2D();
  gc.setFill(Color.GREENYELLOW);
  gc.fillRect(0, 0, width, height);
}

If we look at your method, you are doing a few things that can cause problems.

But first, as you noticed, the statement:

VBox.setVgrow(canvas, Priority.ALWAYS);

is causing you trouble. So let's just get rid of it and use your current structure.

If we just change your listeners from canvas to box:

canvas.heightProperty().addListener(observable -> draw());
canvas.widthProperty().addListener(observable -> draw());

to

box.heightProperty().addListener(observable -> draw());
box.widthProperty().addListener(observable -> draw());

We will now dynamically update things as your Vbox size changes. This means that your method draw will not be called when we resize, it wasn't doing that before so that's good!

So now back to the draw method. First of all, you are asking for the canvas width each time, when really we care about getting the canvas to match the box, so let's change that from canvas to box (You'll declare your Vbox as a field now).

private void draw() {
  final double width = box.getWidth();
  final double height = box.getHeight();
  System.out.println("w, h: " + width + "; " + height);
  final GraphicsContext gc = canvas.getGraphicsContext2D();
  gc.setFill(Color.GREENYELLOW);
  gc.fillRect(0, 0, width, height);
}

But this still won't work very well. That's because we never update the canvas size! So let's add a setWidth and a setHeight in

private void draw() {
  final double width = box.getWidth();
  final double height = box.getHeight();
  canvas.setWidth(width);
  canvas.setHeight(height);
  System.out.println("w, h: " + width + "; " + height);
  final GraphicsContext gc = canvas.getGraphicsContext2D();
  gc.setFill(Color.GREENYELLOW);
  gc.fillRect(0, 0, width, height);
}

With that, we'll notice that everything seems to be looking pretty good, with one exception. The button is now blocking the top of the screen and will make it so that you can't actually fill that top part. That's because the button was drawn first onto the screen and gets priority (If we switch it to be added at index 1 via a different add method call, we see the button disappears). I can't think of a way to fix that right now, but hopefully that solves part of your problem!

Upvotes: 1

Related Questions