每当javafx.stage.Stage
根节点的首选宽度/高度发生变化时,我想自动调整Scene
的宽度/高度。
它是一个包含多个javafx.scene.control.TitledPane
s的小实用程序窗口(不可由用户调整大小),当其中一个TitledPanes扩展时,窗口的高度应该会增加(否则TitlePane&#39 ; s内容可能超出界限)。
不幸的是,我只能找到javafx.stage.Window.sizeToScene()
,它最初将窗口的大小设置为根目录的首选大小。
有没有办法将Stage大小永久绑定到根节点大小?
答案 0 :(得分:2)
根据DVarga的例子,我制作了以下"解决方案":
InvalidationListener
安装在每个子节点的heightProperty
上,可能会缩小/增加高度(本例中为两个TitlePanes
)。
当heightProperty
无效时,将重新计算包含窗口的高度(同样遵循窗口装饰)。
示例:强>
public class SampleApp extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
final Label lbl1 = new Label("content");
final TitledPane tp1 = new TitledPane("First TP", lbl1);
final Label lbl2 = new Label("more content");
final TitledPane tp2 = new TitledPane("Second TP", lbl2);
final VBox rootPane = new VBox(tp1, tp2);
tp1.heightProperty().addListener((InvalidationListener) observable -> {
updateWindowHeight(rootPane);
});
tp2.heightProperty().addListener((InvalidationListener) observable -> {
updateWindowHeight(rootPane);
});
final Scene scene = new Scene(rootPane);
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.setResizable(false);
primaryStage.show();
}
private void updateWindowHeight(final VBox rootPane) {
final Scene scene = rootPane.getScene();
if (scene == null)
return;
final Window window = scene.getWindow();
if (window == null)
return;
final double rootPrefHeight = rootPane.prefHeight(-1);
final double decorationHeight = window.getHeight() - scene.getHeight(); // window decorations
window.setHeight(rootPrefHeight + decorationHeight);
}
public static void main(String[] args) {
launch(args);
}
}
尽管它按预期工作,但此解决方案存在一些主要缺点:
我无法获得更清洁的解决方案。 javafx.stage.Stage
和javafx.scene.Scene
过于受阻(可能的扩展点是最终的或包私有的)来实现它所属的此功能。
<强>更新强>
仅使用window.sizeToScene()
代替
final double rootPrefHeight = rootNode.prefHeight(-1);
final double decorationHeight = window.getHeight() - scene.getHeight();
window.setHeight(rootPrefHeight + decorationHeight);
产生更少的&#34;口吃&#34;调整窗口大小时!
答案 1 :(得分:1)
班级Region
有一个prefHeightProperty和一个prefWidthProperty,班级Stage
有一个setWidth方法和一个setHeight方法。
您可以收听舞台场景的根区域的属性更改,并且在侦听器中可以调用舞台的相应mutator方法:
root.prefHeightProperty().addListener((obs, oldVal, newVal) -> primaryStage.setHeight(newVal.doubleValue()));
root.prefWidthProperty().addListener((obs, oldVal, newVal) -> primaryStage.setWidth(newVal.doubleValue()));
我用于测试的一个例子:
public class Main extends Application {
@Override
public void start(final Stage primaryStage) {
try {
// Add some controls to set the pref size of the root VBox
final VBox par = new VBox();
final TextField tf1 = new TextField();
final TextField tf2 = new TextField();
Button b1 = new Button();
b1.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
// On button press set the pref size of the VBox to the values of the TextFields
par.setPrefSize(Double.parseDouble(tf1.getText()), Double.parseDouble(tf2.getText()));
}
});
par.getChildren().addAll(tf1, tf2, b1);
Scene scene = new Scene(par,400,400);
// Attach the listeners
par.prefHeightProperty().addListener((obs, oldVal, newVal) -> primaryStage.setHeight(newVal.doubleValue()));
par.prefWidthProperty().addListener((obs, oldVal, newVal) -> primaryStage.setWidth(newVal.doubleValue()));
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Layouts通过调用来查询节点的首选大小 prefWidth(高度)和prefHeight(宽度)方法。默认情况下,UI 控制计算其首选大小的默认值 关于控件的内容。例如,a的计算大小 Button对象由文本的长度和大小决定 用于标签的字体,加上任何图像的大小。通常情况下, 计算出的大小对于控件和标签而言足够大 完全可见。
UI控件还提供默认的最小和最大尺寸 基于控件的典型用法。例如,最大值 Button对象的大小默认为其首选大小,因为您 通常不希望按钮增长任意大。然而 ScrollPane对象的最大大小是无限制的,因为通常是你 希望他们成长以填补他们的空间。
基于此,我们的想法是以ScrollPane
为根,使用隐藏的滚动条,因为此控件允许内容自由地&#34;成长。
随着内容的增长,您可以收听ScrollPane内容的heightProperty
和widthProperty
,并设置Stage
的大小。
示例:强>
public class Main extends Application {
@Override
public void start(final Stage primaryStage) {
try {
// ScrollPane will be the root
ScrollPane sp = new ScrollPane();
// Don't show the ScrollBars
sp.setHbarPolicy(ScrollBarPolicy.NEVER);
sp.setVbarPolicy(ScrollBarPolicy.NEVER);
// TitledPane will be the content of the root
TitledPane tp = new TitledPane();
sp.setContent(tp);
// Set the layout bounds of the TitledPane
tp.setMinHeight(400);
tp.setMinWidth(400);
tp.setMaxHeight(900);
tp.setMaxWidth(900);
// Fill the TitledPane with some Buttons and containers to test the growing and shrinking progress
final VBox vboxTPContentVertical = new VBox();
final VBox vboxTexts = new VBox();
final HBox hboxTexts = new HBox();
HBox hboxButtons = new HBox();
vboxTPContentVertical.getChildren().addAll(hboxButtons, hboxTexts, vboxTexts);
Button b1 = new Button("Add row");
b1.setOnAction((event) -> vboxTexts.getChildren().addAll(new Text("Row1"), new Text("Row2")));
Button b2 = new Button("Add column");
b2.setOnAction((event) -> hboxTexts.getChildren().addAll(new Text("Col1"), new Text("Col2")));
Button b3 = new Button("Remove row");
b3.setOnAction((event) -> {
vboxTexts.getChildren().remove(0);
vboxTexts.getChildren().remove(0);
});
Button b4 = new Button("Remove column");
b4.setOnAction((event) -> {
hboxTexts.getChildren().remove(0);
hboxTexts.getChildren().remove(0);
});
hboxButtons.getChildren().addAll(b1, b2, b3, b4);
tp.setContent(vboxTPContentVertical);
// Set the ScrollPane as root
Scene scene = new Scene(sp, 400, 400);
// Now just listen to the heightProperty and widthProperty of the TitledPane
tp.heightProperty().addListener((obs, oldVal, newVal) -> primaryStage.setHeight(to.doubleValue()));
tp.widthProperty().addListener((obs, oldVal, newVal) -> primaryStage.setWidth(to.doubleValue()));
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}