简体   繁体   English

调整拆分窗格的大小时,如何将 JavaFx 节点保持在其原始位置?

[英]How do I keep JavaFx nodes in their original positions when resizing a split pane?

I currently have a splitPane with 3 AnchorPanes, the center pane (Graph) of which contains some Circles contained in StackPanes that I add to the center AnchorPane in my code.我目前有一个带有 3 个 AnchorPane 的 splitPane,其中的中心窗格(图表)包含 StackPanes 中包含的一些 Circles,我在代码中添加到中心 AnchorPane。 When I resize the left divider, the contents of the center graph AnchorPane move with the left divider.当我调整左分隔线的大小时,中心图 AnchorPane 的内容会随着左分隔线移动。

Is there a way I can keep the nodes in the AnchorPane (or by using some other pane) from moving with the divider?有没有办法让 AnchorPane 中的节点(或使用其他窗格)不随分隔线移动? Even better would be if I could have the "Graph" text move and the circle nodes remain stationary, but that's not necessary.如果我可以让“图形”文本移动并且圆形节点保持静止,那就更好了,但这不是必需的。 I'm new to JavaFx and still not sure how each pane works exactly.我是 JavaFx 的新手,但仍然不确定每个窗格的工作原理。

Here are two screenshots showing the process of resizing that I'm describing.这是两个屏幕截图,显示了我正在描述的调整大小的过程。 Thanks in advance for any help!提前感谢您的帮助!

EDIT: Anko's solution below worked wonderfully for me.编辑:下面的 Anko 解决方案对我来说非常有用。 Thank you to everyone for helping out:)谢谢大家帮忙:)

Shot 1第 1 枪

在此处输入图像描述

Shot 2射击 2

在此处输入图像描述

Add a ChangeListener to the first Divider , calculate and set LayoutX of the objects in the middle pane like in this small example:ChangeListener添加到第一个Divider ,计算并设置中间窗格中对象的LayoutX ,如下面的小示例所示:

Controller Class: Controller Class:

package sample;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.SplitPane;
import javafx.scene.shape.Ellipse;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable {

    @FXML
    private SplitPane splitPane;

    @FXML
    private Ellipse ellipse;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        splitPane.getDividers().get(0).positionProperty().addListener(((observable, oldValue, newValue) -> {
            ellipse.setLayoutX(ellipse.getLayoutX() + (splitPane.getWidth() * oldValue.doubleValue() - splitPane.getWidth() * newValue.doubleValue()));
        }));
    }
}

FXML File: FXML 文件:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Ellipse?>

<SplitPane fx:id="splitPane" dividerPositions="0.4, 0.9" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
  <items>
    <AnchorPane />
      <AnchorPane>
         <children>
            <Ellipse fx:id="ellipse" fill="DODGERBLUE" layoutX="150.0" layoutY="150.0" radiusX="100.0" radiusY="80.0" stroke="BLACK" strokeType="INSIDE" />
         </children>
      </AnchorPane>
      <AnchorPane />
  </items>
</SplitPane>

Preview:预习:

加载时预览 当第一个分隔线向左移动时预览

If you want the nodes in the graph not to move when the dividers are moved, I think the most logical approach is to make them not a part of the SplitPane .如果您希望图表中的节点在移动分隔线时不移动,我认为最合乎逻辑的方法是让它们不属于SplitPane Use a StackPane , with the actual graph at the lowest z-order and the SplitPane at a higher z-order;使用StackPane ,实际图形位于最低 z 顺序, SplitPane位于较高 z 顺序; style the panes contained in the SplitPane so the center pane is transparent and the left and right panes opaque, and make the SplitPane itself have a transparent background.设置SplitPane中包含的窗格的样式,使中央窗格透明,左右窗格不透明,并使SplitPane本身具有透明背景。

This approach relies on standard layout mechanisms, and avoids the need to use listeners to modify the layout after the system updates it.这种方式依赖于标准的布局机制,避免了系统更新后需要使用监听器来修改布局。

Here's a mock-up of this approach:这是这种方法的模型:

import java.io.IOException;
import java.util.stream.Stream;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

/**
 * JavaFX App
 */
public class App extends Application {


    @Override
    public void start(Stage stage) throws IOException {

        BorderPane root = new BorderPane();

        // menu bar in top, status in bottom...

        StackPane graphStack = new StackPane();

        Pane graphPane = new Pane();
        populateGraphPane(graphPane);

        VBox controls = new VBox(5,
            new Label("Controls"),
            new Button("A Button"),
            new TextField()
        );

        AnchorPane graphOverlay = new AnchorPane();
        Label graphLabel = new Label("Graph");
        AnchorPane.setTopAnchor(graphLabel, 5.0);
        AnchorPane.setLeftAnchor(graphLabel, 5.0);
        graphOverlay.getChildren().add(graphLabel);

        VBox details = new VBox(5, new Label("Details"));

        SplitPane split = new SplitPane(controls, graphOverlay, details);
        graphStack.getChildren().addAll(graphPane, split);
        split.setDividerPositions(0.33, 0.67);

        // Styles: IRL do this in an external CSS style sheet
        // Make the background white, but make the overlay transparent so we see the graph below it:
        graphPane.setStyle("-fx-background-color: white ;");
        controls.setStyle("-fx-background-color: white ; -fx-color: red ; -fx-focus-color: #FF7F50 ; -fx-faint-focus-color: #FF7F5022 ; -fx-padding: 5 ; ");
        details.setStyle("-fx-background-color: white ; -fx-padding: 5 ;");
        graphOverlay.setStyle("-fx-background-color: transparent ;");
        split.setStyle("-fx-background-color: transparent ;");

        root.setStyle("-fx-text-background-color: red ;");

        root.setCenter(graphStack);

        Scene scene = new Scene(root, 800, 600);
        stage.setScene(scene);
        stage.show();
    }

    private void populateGraphPane(Pane graph) {
        Circle top = new Circle(400, 200, 20, Color.WHITE);
        Circle left = new Circle(300, 373, 20, Color.WHITE);
        Circle right = new Circle(500, 373, 20, Color.WHITE);
        Line leftLine = new Line(390, 217, 310, 356);
        Line rightLine = new Line(410, 217, 490, 356);
        Line bottomLine = new Line(320, 373, 480, 373);

        Stream.of(top, left, right).forEach(c -> {
            c.setStroke(Color.RED);
            c.setStrokeWidth(3);
        });

        Stream.of(leftLine, rightLine, bottomLine).forEach(l -> {
            l.setStroke(Color.RED);
            l.setStrokeWidth(3);
        });

        Group group = new Group();
        group.getChildren().addAll(top, left, right, leftLine, rightLine, bottomLine);
        graph.getChildren().add(group);
    }



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

}

and some screenshots:和一些截图:

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

If you want to avoid obscuring parts of the graph, it's relatively easy to do so by setting min/max widths on the panes in the graph (which will restrict the movement of the dividers).如果您想避免遮挡图表的某些部分,可以通过在图表中的窗格上设置最小/最大宽度来相对容易地做到这一点(这将限制分隔线的移动)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM