【发布时间】: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 个节点p1 和p2)超出范围时出现自定义ScrollBar。为了便于测试 - p1 和 p2 在用鼠标拖动时都可以调整大小(试试看)。虽然ScrollBar 出现并按预期工作,但如果我们开始最大化和最小化窗口,布局就会出现缺陷。
例如:
- 启动程序
- 调整内容大小,使
ScrollBar出现,但不要太大 很多(让它在你最大化它时,它会在界限内) - 最大化窗口 - 您会注意到栏可能已经消失,但会出现“空白空间”。
- 现在,如果您以某种方式进行刷新(例如,通过再次调整内容大小),栏将由于布局传递更新而消失。
其他错误:
- 启动程序并最大化。
- 调整内容大小,使其仍包含在最大化的窗口中,但足够大,当您最小化时,它会超出界限。
- 最小化
- 注意
ScrollBar是如何放错位置的。
如果您尝试其他东西,则几乎没有其他错误,但所有错误都源于当您最大化/最小化时会发生这种情况(使用第一个示例):
-
ScrollBar受管理且可见(考虑到内容超出)。 - 最大化
- 计算窗口大小调整布局(使用旧值 - managed=true && visible=true)
- 布局发生,一切就绪,所有属性都收到更新,包括
sb.visibleAmountProperty()将ScrollBar设置为托管和可见为 false(因为它们已绑定,请参阅代码)。 -
ScrollBar变得不可见且不受管理,但布局已经发生,不会重新运行。
如何使它与窗口最大化一起使用?我还能如何绑定ScrollBar,使其在最大化时不会中断?请注意,我们谈论的是最大化,而不是调整大小(可行)。
【问题讨论】: