提问者:小点点

JavaFX:组不在VBox中居中


我想将VBox中的一组节点居中,并在组超出父VBox的边界时缩放该组。

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

节点是动态添加的:myCustomPane. getContentPane().get儿童().addAll(椭圆,线)

不幸的是,(红色)组既不居中,也不在窗口中可见。但是我确实看到了(橙色)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);
  }
}

更新:添加了拖动支持

我尝试为我的节点添加拖动支持,以便我可以检查内部窗格何时重新缩放。我还将组更改为简单窗格,以便我可以使内部窗格的边界可见。不幸的是,内部窗格(红色)不能对子节点进行捕捉。如何强制内容窗格获取其子窗格的大小,并在其大小超过父边界时重新缩放?

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个答案

匿名用户

我想我有这个工作的方式,你想要的,除了缩放给它一个尝试,让我知道,如果它的工作原理,你也不能添加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;
    }
}