开发者

Dynamic/instant resize in JavaFX

How do you create a JavaFX application that (instantly) dynamically resizes? Right now I have coded a simple applica开发者_运维知识库tion that dynamically resizes but the layout changes don't display until after the release of the mouse button on a drag. I want instantly see the results/layout changes before this button release.

I'm assuming this is done by just binding the correct values/controls with inverse... Any help would be great!


EDIT:

Here's how I got things working (thanks to Praeus). Exactly as he said, I had to bind my top level container/layout width and height to scene.width and scene.height. --

var scene: Scene;

Stage {

title: "Application title"

scene: scene = Scene {

content: [

XMigLayout {

width: bind scene.width;

height: bind scene.height;

...}]}}


Bind is different in JavaFX's 2.0 release. Angela Caicedo's video demonstrates how to bind properties nicely. A variable must be setup as an ObservableNumberValue and its get and set methods used. After it's setup you can then bind it to a component's property.

DoubleProperty x = new SimpleDoubleProperty(0);
x.set(1);
x.getValue();
imageView.xProperty().bind(x);
anchorPane.heightProperty().add(x);

Eric Bruno's post is another way of doing it.

scene.widthProperty().addListener( 
    new ChangeListener() {
        public void changed(ObservableValue observable, 
                            Object oldValue, Object newValue) {
            Double width = (Double)newValue;
            tbl.setPrefWidth(width);
        }
    });

scene.heightProperty().addListener(
    new ChangeListener() {
        public void changed(ObservableValue observable, 
                            Object oldValue, Object newValue) {
            Double height = (Double)newValue;
            tbl.setPrefHeight(height);
        }
    });

Edits: Added another, more fitting answer along with where I found it.


Actually if you've already organized everything into layouts, then you might be able to just bind the top level layout container(s) width and height to the scene.width and scene.height. I don't think top level layout controls are managed by anything, so you may be safe just setting width and height of the layout control directly. If that doesn't work then you might have success binding the layoutInfo width and height.

Ideally you want to use layout management before resorting to binds. Excessive binds can be a performance problem, and can lead to slow redraws as you are resizing. In this case you can probably just use binds for the top level container, and then all of the children of the top level container should resize accordingly. At least I think that should work.


Yes I think you're on the right lines - binding would be the obvious way to do what you trying to do. You could also look at triggers.

Read the 1.3 guide to layouts as a starting point if you haven't already

The layout containers automatically manage the dynamic layout behavior of their content nodes. However, it is often desirable to also use the binding mechanism of the JavaFX Script to establish certain dynamic aspects of layout. For example, you can bind the width and height of an HBox container to the Scene height and width so that whenever Scene resizes, the HBox container resizes as well.

It's also probably worth reading articles and blog posts by JavaFX layout guru Amy Fowler


Here's what I ended up doing to get my resizing how I liked. There has to be an easier way but I surely don't know it.

My main method loads my controller and scene then calls my controllers init() method

        FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
    Parent root = (Parent) loader.load();
    primaryStage.setTitle("Robot Interface");
    primaryStage.setScene(new Scene(root));
    primaryStage.show();
    Controller controller = (Controller)loader.getController();
    controller.init();

I am using a gridpane that dynamically resizes as the whole stage is resized by the user so it always fits. This is becaus its percentage sizing. This is done in the fxml way easier than with binding IMO.

<GridPane fx:id="gridPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="700.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">

  <columnConstraints>
    <ColumnConstraints percentWidth="50" />
    <ColumnConstraints percentWidth="50" />
  </columnConstraints>
  <rowConstraints>
    <RowConstraints percentHeight="35" />
    <RowConstraints percentHeight="35" />
    <RowConstraints percentHeight="35" />
  </rowConstraints>
   <children>

      <TextArea fx:id="textArea_Console" prefHeight="200.0" prefWidth="200.0" promptText="console/reponse" GridPane.columnIndex="1" GridPane.rowIndex="2" />

      <!-- <MediaView fx:id="mediaView_Images" fitHeight="225.0" fitWidth="225.0" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM" /> -->


      <TextArea fx:id="textArea_RoboAvail" maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="121.0" prefWidth="123.0" promptText="robots available" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.valignment="TOP" />

      <TextArea fx:id="textArea_SensorData" maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="249.0" prefWidth="106.0" promptText="sensor data" GridPane.halignment="RIGHT" GridPane.valignment="TOP" />

      <TextArea fx:id="textArea_Scripting" prefHeight="200.0" prefWidth="200.0" promptText="Scripting" GridPane.columnIndex="1" GridPane.rowIndex="1" />

      <Label text="Currently Viewing" GridPane.halignment="LEFT" GridPane.valignment="TOP" />

      <TextArea maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="250.0" prefWidth="100.0" promptText="to do list" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.valignment="TOP" />

      <ImageView fx:id="imageView_Images"  fitHeight="233.0" fitWidth="225.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="LEFT" GridPane.valignment="TOP" />

      <Label fx:id="label_CheatSheet" text="Label" GridPane.halignment="LEFT" GridPane.rowIndex="2" GridPane.valignment="BOTTOM" />




   </children>

Remember how my controller class had its init() method called. Well init() calls setupUI where I get my height and width and create callbacks for height and width changes later. Those change my class wide variables mHeight and mWidth;

  private void setupUI()
{
    imageView_Images.setImage( new Image("file:///C:\\Users\\administration\\IdeaProjects\\Robot User Interface\\Media\\filler.jpeg"));



   mHeight = gridPane.getHeight();
   mWidth = gridPane.getWidth();

   //for initial startup sizing
    dynamicRsize();


    //callbacks to detect changes for sizing
    gridPane.widthProperty().addListener(new ChangeListener<Number>() {
        @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            mWidth = newValue.doubleValue();
            dynamicRsize();
        }
    });

    gridPane.heightProperty().addListener(new ChangeListener<Number>() {
        @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            mHeight = newValue.doubleValue();
            dynamicRsize();
        }
    });


    setup_TextArea_Scriptng();
    setup_Label_CheatSheet();

}

Finally I can call dynamicResize() which adjust every object in the gridpane as a percentage of that rows width or height

  private void dynamicRsize()
{
    //two columns 50/50
    //three rows 35/35/30

    double columnType1 = mWidth/2;
    double rowType1 = mHeight * .35;
    double rowType2 = mHeight * .3;

    //node 1
    imageView_Images.setFitWidth(columnType1 * .75);
    textArea_SensorData.setPrefWidth(columnType1 * .25);

   //node 2

    //node 3

    //node 4

    //node 5

    //node 6







}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜