设置SplitPane的分隔位置

时间:2016-03-29 16:58:44

标签: javafx javafx-8

我想将SplitPane的分隔符设置为某个默认位置。这不起作用,分隔线保持在中间:

public void start(Stage primaryStage) throws Exception{

    SplitPane splitPane = new SplitPane(new Pane(), new Pane());

    // Report changes to the divider position
    splitPane.getDividers().get(0).positionProperty().addListener(
            o -> System.out.println(splitPane.getDividerPositions()[0])
    );

    // Doesn't work:
    splitPane.setDividerPositions(0.8);

    // The docs seem to recommend the following (with floats instead of
    // doubles, and with one number more than there are dividers, which is
    // weird), but it doesn't work either:
    //splitPane.setDividerPositions(0.8f, 0.2f);

    primaryStage.setScene(new Scene(splitPane));
    primaryStage.setMaximized(true);
    primaryStage.show();
}

输出:

0.8
0.5

screenshot of result

它表明某些东西会重置到中间。

我怎样才能做到这一点?

8 个答案:

答案 0 :(得分:9)

问题似乎是在最大化SplitPane期间设置Stage的宽度时重置分隔符位置。您应该可以通过监听窗口的showing属性来设置它:

primaryStage.showingProperty().addListener(new ChangeListener<Boolean>() {

    @Override
    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
        if (newValue) {
            splitPane.setDividerPositions(0.8);
            observable.removeListener(this);
        }
    }

});

答案 1 :(得分:0)

Stage初始化期间,窗口大小会多次更改,直到布局完成。每次更改都会修改分隔符位置。如果要控制分隔符位置,则必须在 Stage完全初始化后设置

private boolean m_stageShowing = false;

@Override
public void start(Stage primaryStage) throws Exception {
    SplitPane splitPane = new SplitPane(new Pane(), new Pane());

    ChangeListener<Number> changeListener = new ChangeListener<Number>() {
        @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            splitPane.setDividerPositions(0.8);
            if (m_stageShowing) {
                observable.removeListener(this);
            }
        }
    };
    splitPane.widthProperty().addListener(changeListener);
    splitPane.heightProperty().addListener(changeListener);

    primaryStage.setScene(new Scene(splitPane));
    primaryStage.setMaximized(true);
    primaryStage.show();
    m_stageShowing = true;
}

答案 2 :(得分:0)

我遇到了同样的问题,上面的解决方案对我来说不可靠。 所以我为SplitPane创建了一个自定义皮肤:

public class DumbSplitPaneSkin extends SplitPaneSkin {

  public DumbSplitPaneSkin(SplitPane splitPane) {
    super(splitPane);
  }

  @Override
  protected void layoutChildren(double x, double y, double w, double h) {
    double[] dividerPositions = getSkinnable().getDividerPositions();
    super.layoutChildren(x, y, w, h);
    getSkinnable().setDividerPositions(dividerPositions);
  }
}

此皮肤可以通过css或重写SplitPane.createDefaultSkin()来使用。您还可以以编程方式设置为splitPane.setSkin(new DumbSplitPaneSkin(splitPane));

答案 3 :(得分:0)

您可以使用

打包电话setDividerPositions
Platform.runLater(new Runnable() {

            @Override
            public void run() {
                splitPane.setDividerPositions(0.8);

            }
        });

这不是100%可靠的解决方案,因为run()方法在未指定的时间在JFX线程中执行,但它适用于简单的初始化情况。

答案 4 :(得分:0)

这是我的结果:

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Orientation;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.*;

/**
 * SplitPane, Dialogbox example
 * @author Pataki István
 */
public class SimpleDocking extends Application {

  private double splitPosition = 0;
  private SplitPane rootPane = new SplitPane();
  private MyDialog dialog;
  private BorderPane dockedArea;

  @Override
  public void start(final Stage stage) throws Exception {
    rootPane.setOrientation(Orientation.VERTICAL);
    rootPane.setBorder(new Border(new BorderStroke(
                                    Color.GREEN,
                                    BorderStrokeStyle.SOLID,
                                    new CornerRadii(5),
                                    new BorderWidths(3))
    ));

    dockedArea = new BorderPane(new TextArea("Some docked content"));
    final FlowPane centerArea = new FlowPane();
    final Button undockButton = new Button("Undock");
    centerArea.getChildren().add(undockButton);
    rootPane.getItems().addAll(centerArea, dockedArea);
    stage.setScene(new Scene(rootPane, 300, 300));
    stage.show();

    dialog = new MyDialog(stage);
    undockButton.disableProperty().bind(dialog.showingProperty());
    undockButton.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent actionEvent) {
        handler(stage);
      }
    });
  }

  private void handler(Stage stage) {
    splitPosition = rootPane.getDividerPositions()[0];
    rootPane.getItems().remove(dockedArea);
    dialog.setOnHidden(windowEvent -> {
      rootPane.getItems().add(dockedArea);
      rootPane.setDividerPositions(splitPosition);
    });
    dialog.setContent(dockedArea);
    dialog.show(stage);
  }

  private class MyDialog extends Popup {
    private BorderPane root;

    private MyDialog(Window parent) {
      root = new BorderPane();
      root.setPrefSize(200, 200);
      root.setStyle("-fx-border-width: 1; -fx-border-color: gray");
      root.setTop(buildTitleBar());
      setX(parent.getX() + 50);
      setY(parent.getY() + 50);
      getContent().add(root);
    }

    public void setContent(Node content) {
      root.setCenter(content);
    }

    private Node buildTitleBar() {
      BorderPane pane = new BorderPane();
      pane.setStyle("-fx-background-color: burlywood; -fx-padding: 5");
      final Delta dragDelta = new Delta();

      pane.setOnMousePressed(mouseEvent -> {
        dragDelta.x = getX() - mouseEvent.getScreenX();
        dragDelta.y = getY() - mouseEvent.getScreenY();
      });

      pane.setOnMouseDragged(mouseEvent -> {
        setX(mouseEvent.getScreenX() + dragDelta.x);
        setY(mouseEvent.getScreenY() + dragDelta.y);
      });

      Label title = new Label("My Dialog");
      title.setStyle("-fx-text-fill: midnightblue;");
      pane.setLeft(title);

      Button closeButton = new Button("X");
      closeButton.setOnAction(actionEvent -> hide());
      pane.setRight(closeButton);
      return pane;
    }
  }

  private static class Delta {
    double x, y;
  }

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

这是您想要的作品。

答案 5 :(得分:0)

因为您通常至少在 splitpane 中有一些东西,例如。 vbox,只需设置最小和最大宽度,它就会自动设置分隔线。

答案 6 :(得分:0)

正如其他人所指出的,问题是当舞台最大化时分隔线位置会被重置。

您可以通过将 ResizableWithParent 设置为 false 来防止这种情况发生。

示例

假设您有一个 SplitPane,里面有两个嵌套的容器。这是 fxml 摘录:

<SplitPane fx:id="splitPane" dividerPositions="0.25">
        <VBox fx:id="leftSplitPaneContainer" />
        <FlowPane fx:id="rightSplitPaneContainer"/>
</SplitPane>

这里是控制器类的摘录:

@FXML
private SplitPane splitPane;
@FXML
private VBox leftSplitPaneContainer;
@FXML
private FlowPane rightSplitPaneContainer;

然后您只需在两个容器上调用 SplitPane.setResizableWithParent() 以防止重置分隔符位置:

public void initialize(){
        SplitPane.setResizableWithParent(leftSplitPaneContainer, false);
        SplitPane.setResizableWithParent(rightSplitPaneContainer, false);
    }

即使最大化窗口,分隔线位置现在也将保持在 0.25。

不涉及复杂的侦听器或覆盖 SplitPaneSkin

答案 7 :(得分:-3)

尝试

splitPane.setDividerPosition(0, percentage);

参数是setDividerPosition(int dividerIndex,double percentage)