Set divider position of SplitPane

不想你离开。 提交于 2019-12-08 20:56:34

问题


I want to set the divider of a SplitPane to a certain default position. This does not work, the divider stays in the middle:

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

The output:

0.8
0.5

It suggests that something resets it to the middle.

How can I achieve this?


回答1:


The issue seems to be the divider position being reset when the width of the SplitPane is set during the maximizing of the Stage. You should be able to set it afterwards by listening to the showing property of the window:

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

});



回答2:


During Stage initialization, window size changes several times until layout is completed. Every change modifies divider positions. If you want to control divider positions, they have to be set after Stage is fully initialized:

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



回答3:


I had the same problem and the above solutions where not working reliably for me. So I created a custom skin for 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);
  }
}

This skin can be used via css or by overriding SplitPane.createDefaultSkin(). You can also set programatically as splitPane.setSkin(new DumbSplitPaneSkin(splitPane));




回答4:


You could just wrap the call setDividerPositions with

Platform.runLater(new Runnable() {

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

            }
        });

This is not 100% reliable solution because run() method is performed in JFX thread at unspecified time but it works properly for simple initialization cases.




回答5:


Here is my result:

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

This is works like you wish.




回答6:


Try

splitPane.setDividerPosition(0, percentage);

The parameters are setDividerPosition(int dividerIndex, double percentage)



来源:https://stackoverflow.com/questions/36290539/set-divider-position-of-splitpane

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!