【问题标题】:Maximizing window and layout pass最大化窗口和布局通道
【发布时间】:2017-11-13 22:00:08
【问题描述】:

所以这里的目标是在最大化/最小化窗口时为ScrollPane 使用自定义ScrollBar 而不会出现布局问题。

考虑示例程序:

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 个节点p1p2)超出范围时出现自定义ScrollBar。为了便于测试 - p1p2 在用鼠标拖动时都可以调整大小(试试看)。虽然ScrollBar 出现并按预期工作,但如果我们开始最大化和最小化窗口,布局就会出现缺陷。

例如:

  1. 启动程序
  2. 调整内容大小,使ScrollBar 出现,但不要太大 很多(让它在你最大化它时,它会在界限内)
  3. 最大化窗口 - 您会注意到栏可能已经消失,但会出现“空白空间”。
  4. 现在,如果您以某种方式进行刷新(例如,通过再次调整内容大小),栏将由于布局传递更新而消失。

其他错误:

  1. 启动程序并最大化。
  2. 调整内容大小,使其仍包含在最大化的窗口中,但足够大,当您最小化时,它会超出界限。
  3. 最小化
  4. 注意ScrollBar 是如何放错位置的。

如果您尝试其他东西,则几乎没有其他错误,但所有错误都源于当您最大化/最小化时会发生这种情况(使用第一个示例):

  1. ScrollBar 受管理且可见(考虑到内容超出)。
  2. 最大化
  3. 计算窗口大小调整布局(使用旧值 - managed=true && visible=true)
  4. 布局发生,一切就绪,所有属性都收到更新,包括 sb.visibleAmountProperty()ScrollBar 设置为托管和可见为 false(因为它们已绑定,请参阅代码)。
  5. ScrollBar 变得不可见且不受管理,但布局已经发生,不会重新运行。

如何使它与窗口最大化一起使用?我还能如何绑定ScrollBar,使其在最大化时不会中断?请注意,我们谈论的是最大化,而不是调整大小(可行)。

【问题讨论】:

    标签: java javafx layout


    【解决方案1】:

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

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

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

    为什么不是最好的?好吧,当不是真正需要(而不是最大化)导致双重布局(我们不能用一些 if 语句真正解决这个问题)时,它也会被调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-24
      • 1970-01-01
      • 1970-01-01
      • 2015-07-21
      • 2010-09-23
      相关资源
      最近更新 更多