JavaFX splitpane - 防止不必要的分隔符位置更改

JavaFX splitpane - Prevent unwanted divider position changes

我正在尝试找到一种方法来防止当其中一个分隔线受到 maxWidth 属性 限制时分隔线位置发生变化 属性。

在示例中,我单击按钮以最小化面板,并希望调整中央窗格的大小以容纳可用的额外 space,但额外的 space 会在另外两个面板。

App at run

After clicking left button, right divider has moved

    @Override
public void start(Stage stage) {
    BooleanProperty clicked1 = new SimpleBooleanProperty(false);
    BooleanProperty clicked2 = new SimpleBooleanProperty(false);

    Button button1 = new Button("Click");
    button1.setOnAction(event -> clicked1.set(!clicked1.get()));
    button1.setMaxWidth(800);

    Button button2 = new Button("Click");
    button2.setOnAction(event -> clicked2.set(!clicked2.get()));
    button2.setMaxWidth(800);

    StackPane pane1  = new StackPane(button1);
    StackPane pane2 = new StackPane();
    StackPane pane3  = new StackPane(button2);

    pane1.maxWidthProperty().bind(Bindings.createDoubleBinding(() -> clicked1.get() ? 40.0 : Double.MAX_VALUE, clicked1));
    pane3.maxWidthProperty().bind(Bindings.createDoubleBinding(() -> clicked2.get() ? 40.0 : Double.MAX_VALUE, clicked2));

    SplitPane splitPane = new SplitPane(pane1, pane2, pane3);
    splitPane.setPrefSize(600, 400);
    SplitPane.setResizableWithParent(pane1, false);
    SplitPane.setResizableWithParent(pane3, false);
    splitPane.setDividerPositions(0.25, 0.75);

    stage.setScene(new Scene(splitPane));
    stage.show();
}

您的问题的解决方案是根据修改后的窗格宽度计算和设置分隔线位置。

请在下面找到此逻辑的代码。包括关于要做什么的内联评论。

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class SplitPaneIssue extends Application {

    private double COMPRESSED_WIDTH = 40.0;
    private double D1_DEFAULT_POSITION = 0.25;
    private double D2_DEFAULT_POSITION = 0.75;

    @Override
    public void start(Stage stage) {
        BooleanProperty clicked1 = new SimpleBooleanProperty();
        BooleanProperty clicked2 = new SimpleBooleanProperty();

        Button button1 = new Button("Click");
        button1.setOnAction(event -> clicked1.set(!clicked1.get()));
        button1.setMaxWidth(Double.MAX_VALUE);

        Button button2 = new Button("Click");
        button2.setOnAction(event -> clicked2.set(!clicked2.get()));
        button2.setMaxWidth(Double.MAX_VALUE);

        StackPane pane1 = new StackPane(button1);
        StackPane pane2 = new StackPane();
        StackPane pane3 = new StackPane(button2);

        SplitPane splitPane = new SplitPane(pane1, pane2, pane3);
        splitPane.setPrefSize(600, 400);
        SplitPane.setResizableWithParent(pane1, false);
        SplitPane.setResizableWithParent(pane3, false);
        splitPane.setDividerPositions(D1_DEFAULT_POSITION, D2_DEFAULT_POSITION);

        clicked1.addListener((obs, old, val) -> {
            // First compute the total width of all panes and the percentage value per pixel
            double percentPerPx = 1 / (pane1.getWidth() + pane2.getWidth() + pane3.getWidth());
            // Set the max width based on the toggle value
            pane1.setMaxWidth(val ? COMPRESSED_WIDTH : Double.MAX_VALUE);

            // Now compute the divider positions with the new width.
            double d1 = val ? COMPRESSED_WIDTH * percentPerPx : D1_DEFAULT_POSITION;
            // Computing the width percentage for the pane3 and subtracting from 1 will retain its position.
            double d2 = 1 - (pane3.getWidth() * percentPerPx);
            splitPane.setDividerPositions(round(d1), round(d2));
        });
        clicked2.addListener((obs, old, val) -> {
            double percentPerPx = 1 / (pane1.getWidth() + pane2.getWidth() + pane3.getWidth());
            pane3.setMaxWidth(val ? COMPRESSED_WIDTH : Double.MAX_VALUE);
            double d1 = pane1.getWidth() * percentPerPx;
            double d2 = val ? 1 - (COMPRESSED_WIDTH * percentPerPx) : D2_DEFAULT_POSITION;
            splitPane.setDividerPositions(round(d1), round(d2));
        });
        stage.setScene(new Scene(splitPane));
        stage.show();
    }

    private double round(double value) {
        long factor = (long) Math.pow(10, 2);
        value = value * factor;
        long tmp = Math.round(value);
        return (double) tmp / factor;
    }
}