JavaFX:组不在VBox中居中

时间:2017-11-30 14:52:57

标签: javafx javafx-8

我希望将一组节点置于VBox中心,如果超过父VBox的范围,则缩放该组。

我尝试了以下设置:ScrollPane包含一个VBox,它应该以一组节点为中心(例如Circles,Lines等)。

动态添加节点:myCustomPane.getContentPane().getChildren().addAll(ellipse, line)

不幸的是,(红色)组在窗口上既不居中也不可见。但是我确实看到了(橙色)ScalablePane,(蓝色)VBox和所有节点。

public class ScalablePane extends ScrollPane {

    private Property<Group> contentPaneProperty = new SimpleObjectProperty<>();
    public ScalablePane() {
        setContentPane(new Group());
        setPannable(true);
        setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setFitToHeight(true); // center
        setFitToWidth(true); // center
        setStyle("-fx-background-color: orange;");
    }

    public final void setContentPane(Group contentPane) {
        contentPane.setManaged(false);
        contentPane.setStyle("-fx-background-color: red;");

        VBox vBox = new VBox();
        vBox.setAlignment(Pos.CENTER);
        vBox.setManaged(true);
        vBox.getChildren().add(contentPane);
        vBox.setStyle("-fx-background-color: blue;");

        setContent(vBox);
        contentPaneProperty.setValue(contentPane);
     }

     public Group getContentPane() {
        return contentPaneProperty.getValue();
     }
}

用法:

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) {
    try {
      ScalablePane pane = new ScalablePane();
      Circle circle = new Circle(200, 40, 20);
      Circle circle2 = new Circle(100, 150, 20);

      pane.getContentPane().getChildren().addAll(circle, circle2);

      Scene scene = new Scene(pane, 400, 400);
      primaryStage.setScene(scene);
      primaryStage.sizeToScene();
      primaryStage.show();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    launch(args);
  }
}

更新:添加了拖动支持

我尝试为节点添加拖动支持,因此我可以检查内部窗格何时重新缩放。我还将Group更改为一个简单的Pane,这样我就可以看到内部窗格的边界。不幸的是,内部窗格(红色)不会捕捉到子节点。如何强制内容窗格,以获取其子项的大小,并在其大小超过父级边界时重新调整大小?

public class ScalablePane extends ScrollPane {

  private final Pane contentPane;
  private final Scale contentScaleTransform;

  public ScalablePane() {
    contentPane = new Pane();
    contentScaleTransform = new Scale(1, 1);

    initializeScrollPane();
    initializeContentPane();
  }

  public void initializeScrollPane() {
    setPannable(true);
    setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
    setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
    setFitToHeight(true); // center
    setFitToWidth(true); // center
    setStyle("-fx-background-color: orange;");
  }

  private final void initializeContentPane() {
    contentPane.setStyle("-fx-background-color: red;");

    VBox vBox = new VBox();
    VBox.setMargin(contentPane, new Insets(10));
    vBox.setAlignment(Pos.CENTER);
    vBox.setManaged(true);
    vBox.getChildren().add(contentPane);
    vBox.setStyle("-fx-background-color: blue;");

    setContent(vBox);

    contentPane.layoutBoundsProperty()
        .addListener(new ChangeListener<Bounds>() {
          @Override
          public void changed(ObservableValue<? extends Bounds> observable,
              Bounds oldValue, Bounds newValue) {

            double parentWidth = getContentPane().getParent().getLayoutBounds()
                .getWidth() - 10;
            double parentHeight = getContentPane().getParent().getLayoutBounds()
                .getHeight() - 10;

            if (parentHeight > 0 && parentWidth > 0) {
              if (newValue.getHeight() > parentHeight
                  || newValue.getWidth() > parentWidth) {
                computeScale();
              }
            }
          }
        });
  }

  public void computeScale() {
    double realWidth = getContentPane().prefWidth(getWidth());
    double realHeight = getContentPane().prefHeight(getHeight());

    double leftAndRight = getInsets().getLeft() + getInsets().getRight();
    double topAndBottom = getInsets().getTop() + getInsets().getBottom();

    double contentWidth = getWidth() - leftAndRight;
    double contentHeight = getHeight() - topAndBottom;

    double scaleX = contentWidth / realWidth;
    double scaleY = contentHeight / realHeight;

    double scale = Math.min(scaleX, scaleY);
    getContentScaleTransform().setX(scale);
    getContentScaleTransform().setY(scale);

    getContentPane().resize(contentWidth / getContentScaleTransform().getX(),
        contentHeight / getContentScaleTransform().getY());
  }

  public Pane getContentPane() {
    return contentPane;
  }

  public final Scale getContentScaleTransform() {
    return contentScaleTransform;
  }
}

用法:

public class Main extends Application {

  private double dragOriginalSceneX;
  private double dragOriginalSceneY;

  @Override
  public void start(Stage primaryStage) {
    try {
      ScalablePane pane = new ScalablePane();
      Circle circle = new Circle(200, 40, 20);
      Circle circle2 = new Circle(100, 150, 20);
      addDragSupport(circle, pane);
      addDragSupport(circle2, pane);

      pane.getContentPane().getChildren().addAll(circle, circle2);

      Scene scene = new Scene(pane, 400, 400);
      primaryStage.setScene(scene);
      primaryStage.sizeToScene();
      primaryStage.show();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    launch(args);
  }


  private void addDragSupport(Circle node, ScalablePane graphPane) {
    node.setOnMousePressed(e -> {
      dragOriginalSceneX = e.getSceneX()
          / graphPane.getContentScaleTransform().getX();
      dragOriginalSceneY = e.getSceneY()
          / graphPane.getContentScaleTransform().getY();
    });

    node.setOnMouseDragged(e -> {
      Circle circle = (Circle) e.getSource();
      circle.setManaged(true);
      double eventX = e.getSceneX()
          / graphPane.getContentScaleTransform().getX();
      double eventY = e.getSceneY()
          / graphPane.getContentScaleTransform().getY();

      double offsetX = eventX - dragOriginalSceneX;
      double offsetY = eventY - dragOriginalSceneY;

      double newX = circle.getCenterX() + offsetX;
      double newY = circle.getCenterY() + offsetY;

      circle.setCenterX(newX);
      circle.setCenterY(newY);

      // remember last coordinates
      dragOriginalSceneX = eventX;
      dragOriginalSceneY = eventY;
    });
  }

1 个答案:

答案 0 :(得分:0)

我认为我按照您想要的方式工作,除了缩放尝试让我知道它是否有效也是你不能将css添加到一个组中这是一个小组可以做的事情的例子,如果你正在寻找更多 信息https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#group

import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;

public class ScalablePane extends ScrollPane {

//    private Property<Group> contentPaneProperty = new SimpleObjectProperty<>();
    private Group contentPane = new Group();

    public ScalablePane() {
        setContentPane(/*new Group()*/);
        setPannable(true);
        setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setFitToHeight(true); // center
        setFitToWidth(true); // center
        setStyle("-fx-background-color: orange;");
    }

    public final void setContentPane(/*Group contentPane*/) {
//        contentPane.setManaged(false);
        contentPane.setStyle("-fx-background-color: red;");

        VBox vBox = new VBox();
        vBox.setAlignment(Pos.CENTER);
        vBox.setManaged(true);
        vBox.getChildren().add(contentPane);
        vBox.setStyle("-fx-background-color: blue;");

        setContent(vBox);
//        contentPaneProperty.setValue(contentPane);
    }

    public Group getContentPane() {
        return contentPane;
    }
}