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

问题描述 投票:-1回答:2

我目前有一个带有3个AnchorPanes的splitPane,其中央窗格(图形)包含StackPanes中包含的一些Circle,这些圆已在我的代码中添加到中央AnchorPane中。当我调整左分隔线的大小时,中心图AnchorPane的内容随左分隔线移动。

有没有一种方法可以使AnchorPane中的节点(或通过使用其他窗格)不随分隔器一起移动?更好的是,如果我可以移动“图形”(Graph)文本并且使圆形节点保持静止,但这不是必需的。我是JavaFx的新手,仍然不确定每个窗格的工作原理。

这里有两个屏幕快照,显示了我正在描述的调整大小的过程。预先感谢您的帮助!

编辑:Anko的以下解决方案对我来说效果很好。谢谢大家的帮助:)

拍摄1

enter image description here

拍摄2

enter image description here

java user-interface javafx
2个回答
0
投票

如果您希望图形中的节点在分隔线移动时不移动,我认为最合乎逻辑的方法是使它们不成为SplitPane的一部分。使用StackPane,实际图形的Z阶最低,而SplitPane的Z阶更高。对SplitPane中包含的窗格进行样式设置,以使中心窗格透明,而左右窗格不透明,并使SplitPane本身具有透明背景。

此方法依赖于标准布局机制,并且避免了在系统更新布局后使用侦听器修改布局的需求。

这里是这种方法的模型:

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();
    }

}

和一些屏幕截图:

enter image description here

enter image description here

enter image description here

如果要避免遮挡图形的某些部分,通过在图形的窗格中设置最小/最大宽度(这会限制分隔线的移动),这样做相对容易。


0
投票

在第一个ChangeListener中添加Divider,计算并设置中间窗格中对象的LayoutX,就像这个小示例一样:

控制器类:

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文件:

<?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 when loadedpreview when first divider moved to the left

© www.soinside.com 2019 - 2024. All rights reserved.