当我在设置了最大尺寸的透明窗口上调用
sizeToScene
时遇到问题。
假设我将 StackPane 的 prefWidth 设置为大于舞台的 maxWidth。当我显示舞台时,它会考虑舞台的最大宽度并相应地调整 StackPane 宽度。但之后,如果我为 StackPane 设置相同的 prefWidth(或者实际上任何大于 Stage 的 maxWidth 的值)并调用 sizeToScene(),内容舞台将以不同的方式呈现。
在下面的演示中,我将透明舞台最大宽度设置为 200px。并将 StackPane prefWidth 设置为 300px。当舞台显示时,StackPane 将其宽度调整为 200px,这很好。
当我单击标签时,如果我调用 sizeToScene,则内容宽度将根据 prefSizes 进行更新,并且不考虑舞台的最大值。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class SizeToSceneOnTransparentWindow_Demo extends Application {
Stage stage;
@Override
public void start(Stage primaryStage) throws Exception {
Button show = new Button("Show");
show.setOnAction(e -> {
if(stage==null) {
stage = new Stage();
stage.initStyle(StageStyle.TRANSPARENT);
stage.setMaxWidth(200);
Label label = new Label("Test");
StackPane container = new StackPane(label);
container.setStyle("-fx-background-color:#FF000050;-fx-border-width:2px;-fx-border-color:#888888;");
container.setPrefSize(300, 300);
label.setOnMouseClicked(e1 -> {
stage.sizeToScene();
});
StackPane root = new StackPane(container);
stage.setScene(new Scene(root));
stage.setX(200);
stage.setY(200);
}
stage.show();
});
Button hide = new Button("Hide");
hide.setOnAction(e -> stage.hide());
Scene scene = new Scene(new HBox(10,show, hide), 200,200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
这是一个 JavaFX 错误还是应该有这样的行为?因为我观察到 sizeToScene() 方法是在
Window
类中定义的,最大尺寸是在 Stage
类中定义的,很明显 sizeToScene() 方法不会考虑最大值。
sizeToScene 的文档如下:
设置此窗口的宽度和高度以匹配窗口的大小 此窗口场景的内容。
如果窗口不允许这样做,则此请求可能会被忽略, 例如,舞台可能会最大化或全屏,因此 不允许此请求。如果是这样的话,这个请求就是 记住并在允许的情况下重新应用。
文档说明了有关调整窗口大小的信息,但在上述情况下,情况并非如此。场景或内容已调整大小。
这似乎是一个错误,如果您愿意,您可以将其归档。
您可以通过设置场景根的最大尺寸来解决这个问题,例如:
Node root = stage.getScene().getRoot();
设置一次值:
root.setMaxWidth(stage.maxWidthProperty());
追踪价值:
root.maxWidthProperty().bind(stage.maxWidthProperty());
如果您还想考虑舞台或窗口最大/最小函数中的场景变化,那么事情会更复杂。
因为我观察到 sizeToScene() 方法是在 Window 类中定义的,而最大尺寸是在 Stage 类中定义的,很明显 sizeToScene() 方法不会考虑最大值。
它并不像看起来那么明显,因为 sizeToScene 的实现委托给辅助方法。 此外,Stage(或 Stage 子类中的代码)可以覆盖 sizeToScene,尽管 stage 在 JavaFX 23 中不会这样做。
如果你好奇的话,Window中更改句柄大小的代码是:
/**
* Indicates if a user requested the window to be sized to match the scene
* size.
*/
private boolean sizeToScene = false;
/**
* Set the width and height of this Window to match the size of the content
* of this Window's Scene.
*/
public void sizeToScene() {
if (getScene() != null && peer != null) {
SceneHelper.preferredSize(getScene());
adjustSize(false);
} else {
// Remember the request to reapply it later if needed
sizeToScene = true;
}
}
private void adjustSize(boolean selfSizePriority) {
if (getScene() == null) {
return;
}
if (peer != null) {
double sceneWidth = getScene().getWidth();
double cw = (sceneWidth > 0) ? sceneWidth : -1;
double w = -1;
if (selfSizePriority && widthExplicit) {
w = getWidth();
} else if (cw <= 0) {
w = widthExplicit ? getWidth() : -1;
} else {
widthExplicit = false;
}
double sceneHeight = getScene().getHeight();
double ch = (sceneHeight > 0) ? sceneHeight : -1;
double h = -1;
if (selfSizePriority && heightExplicit) {
h = getHeight();
} else if (ch <= 0) {
h = heightExplicit ? getHeight() : -1;
} else {
heightExplicit = false;
}
peerBoundsConfigurator.setSize(w, h, cw, ch);
applyBounds();
}
}
当舞台显示或场景无效时,传递给 adjustmentSize 的 selfSizePriority 为 true,因此它将尺寸优先级赋予窗口约束,但是当您调整场景大小时 selfSizePriority 为 false,它仅将尺寸优先级赋予场景约束。