最大化窗口和布局通过

时间:2017-11-13 22:00:08

标签: java javafx layout

此处的目标是为ScrollBar使用自定义ScrollPane,而不会在最大化/最小化窗口时遇到布局问题。

考虑示例程序:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Layout extends Application
{
    @Override
    public void start(Stage stage)
    {
        BorderPane main = new BorderPane();
        main.setPrefSize(800, 600);

        BorderPane center = new BorderPane(); // begin center
        center.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
        main.setCenter(center); // end center

        BorderPane left = new BorderPane(); // begin left

        ScrollPane pane = new ScrollPane();
        pane.setFitToWidth(true);

        Pane p1 = new Pane(); // child 1
        p1.setPrefSize(200, 100);
        p1.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
        this.makeResizable(p1);
        Pane p2 = new Pane(); // child 2
        p2.setPrefSize(200, 100);
        p2.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
        this.makeResizable(p2);
        VBox content = new VBox(10, p1, p2); // content in scroll pane
        pane.setContent(content);

        // replace normal bars
        pane.setHbarPolicy(ScrollBarPolicy.NEVER);
        pane.setVbarPolicy(ScrollBarPolicy.NEVER);

        // with custom
        ScrollBar sb = new ScrollBar();
        sb.setOrientation(Orientation.VERTICAL);
        sb.minProperty().bind(pane.vminProperty());
        sb.maxProperty().bind(pane.vmaxProperty());
        sb.visibleAmountProperty().bind(pane.heightProperty().divide(content.heightProperty()));
        sb.managedProperty().bind(sb.visibleAmountProperty().lessThan(1.0)); // bar should be managed when it is needed (content too long)
        sb.visibleProperty().bind(sb.managedProperty()); // and also visible only when managed
        sb.valueProperty().bindBidirectional(pane.vvalueProperty());

        left.setCenter(pane); // content
        left.setRight(sb); // scroll bar
        main.setLeft(left); //end left

        Scene scene = new Scene(main);
        stage.setScene(scene);
        stage.show();
    }

    // Simple for testing
    double prevY;
    boolean dragging;

    // Makes node resizable on drag.
    private void makeResizable(Region region)
    {
        region.addEventFilter(MouseEvent.MOUSE_PRESSED, e ->
        {
            this.dragging = true;
            region.setPrefHeight(region.getHeight());
            this.prevY = e.getSceneY();
        });
        region.addEventFilter(MouseEvent.MOUSE_DRAGGED, e ->
        {
            if (!this.dragging) return;
            region.setPrefHeight(region.getPrefHeight() + (e.getSceneY() - this.prevY));
            this.prevY = e.getSceneY();
        });
        region.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> this.dragging = false);
    }

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

它会在左侧生成带有ScrollPane的GUI,并在内容(2个节点ScrollBarp1)超出边界时显示自定义p2。为了便于测试 - 使用鼠标拖动它们时,p1p2都可以调整大小(试一试)。虽然ScrollBar出现并按预期工作,但如果我们开始最大化和最小化窗口,则布局存在缺陷。

例如:

  1. 启动程序
  2. 调整内容大小以显示ScrollBar,但不是 很多(当你最大化它时,它会在界限内)
  3. 最大化窗口 - 您会注意到栏可能已消失,但会出现“空白区域”。
  4. 现在,如果您以某种方式进行刷新(例如通过再次调整内容大小),bar会因布局更新而消失。
  5. 其他错误:

    1. 启动程序并最大化。
    2. 调整内容大小以使其仍包含在最大化窗口中,但足够大,当您最小化时,它将超出边界。
    3. 最小化
    4. 注意ScrollBar是如何放错位置的。
    5. 如果您尝试其他东西,还有很少的其他错误,但所有这些都源于这样一个事实:当您最大化/最小化时(使用第一个示例):

      1. ScrollBar受管理且可见(考虑到内容超出)。
      2. 最大化
      3. 调整窗口大小调整布局(使用旧值 - managed = true&& visible = true)
      4. 布局发生,一切都到位,所有属性都会收到更新,包括sb.visibleAmountProperty()使ScrollBar设置为托管且可见为false(因为它们已绑定,请参阅代码)。
      5. ScrollBar变得不可见且不受管理,但布局已经发生,并且不会重新运行。
      6. 如何使窗口最大化?我怎么能绑定ScrollBar所以它在最大化时不会破坏?请注意,我们谈论的是最大化,而不是调整大小(有效)。

1 个答案:

答案 0 :(得分:0)

我找到了一个解决方法,但这似乎不是绝对最好的事情,如果有更合适的 - 请分享。

sb.managedProperty().addListener(e -> Platform.runLater(() -> content.requestLayout()));

由于这将在“稍后”运行(并且因为也在第一个应完成先前布局的主线程上),这将导致重新布局发生。

为什么不是最好的?好吧,如果没有真正需要(虽然不是最大化)会导致双重布局(我们不能用if语句真正重新调整它)。