java - JavaFX中如何让Canvas填满BorderPane的中心?
问题描述
到目前为止,这是我的代码(在 SceneBuilder 中完成)。
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<Canvas fx:id="canvas" onMouseClicked="#createNode" BorderPane.alignment="CENTER" />
</center>
<right>
<ScrollPane fitToWidth="true" hbarPolicy="NEVER" minViewportWidth="138.0" minWidth="-Infinity" prefHeight="375.0" prefViewportWidth="138.0" prefWidth="138.0" BorderPane.alignment="CENTER">
<content>
<VBox alignment="TOP_CENTER" minWidth="-Infinity" prefHeight="140.0" prefWidth="133.0">
<children>
<Label text="Graph Type" underline="true">
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
</Label>
<RadioButton fx:id="directedButton" mnemonicParsing="false" selected="true" text="Directed">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
<toggleGroup>
<ToggleGroup fx:id="graphType" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="undirectedButton" mnemonicParsing="false" text="Undirected" toggleGroup="$graphType">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</RadioButton>
<Label alignment="TOP_CENTER" text="Diagram Tools" underline="true">
<VBox.margin>
<Insets />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Label>
<ToggleButton fx:id="selectButton" mnemonicParsing="false" selected="true" text="Select">
<toggleGroup>
<ToggleGroup fx:id="diagramTools" />
</toggleGroup>
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</ToggleButton>
<ToggleButton fx:id="nodeButton" mnemonicParsing="false" text="Node" toggleGroup="$diagramTools">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</ToggleButton>
<ToggleButton fx:id="edgeButton" mnemonicParsing="false" text="Edge" toggleGroup="$diagramTools">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</ToggleButton>
<Label text="Diagram Actions" underline="true">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Label>
<VBox alignment="TOP_CENTER" prefHeight="151.0" prefWidth="120.0">
<children>
<Button mnemonicParsing="false" text="DFS">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</Button>
<Button layoutX="52.0" layoutY="41.0" mnemonicParsing="false" text="BFS">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</Button>
<Button layoutX="53.0" layoutY="73.0" mnemonicParsing="false" text="Shortest Path">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</Button>
<Button layoutX="27.0" layoutY="102.0" mnemonicParsing="false" text="Hamilton Path" />
<Button layoutX="24.0" layoutY="134.0" mnemonicParsing="false" text="Hamilton Cycle">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</Button>
<Button layoutX="22.0" layoutY="163.0" mnemonicParsing="false" text="Eulerian Path">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</Button>
<Button layoutX="27.0" layoutY="191.0" mnemonicParsing="false" text="Eulerian Cycle">
<VBox.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</VBox.margin>
</Button>
</children>
</VBox>
</children>
</VBox>
</content>
</ScrollPane>
</right>
<left>
<VBox prefHeight="375.0" prefWidth="119.0" style="-fx-background-color: black;" BorderPane.alignment="CENTER" />
</left>
</BorderPane>
我在右侧有一个由 ScrollPane 制成的工具栏,当窗口缩小时,工具栏在窗口中保持可见。顶部和左侧将被占用,底部为空。我希望中心是一个随着窗口大小变化而缩小和增长的画布,以填充其余空间。但在 SceneBuilder 中,我只能设置固定的宽度/高度。
无论窗口大小如何,我怎样才能让 BorderPane 的中心画布自动填充任何未占用的空间?可以在 SceneBuilder 中完成,还是只能在我的 Controller 或 FXML 文件本身中完成?
编辑:这是我的主要课程,以尽量减少可重复的示例,尽管它只是设置它。控制器类Controller
本质上是空的。
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample1.fxml"));
stage.setTitle("Sample 2");
stage.setScene(new Scene(root, 500, 500));
stage.show();
}
}
解决方案
ACanvas
不是可调整大小的节点,因此默认情况下不会调整大小。您必须安排setWidth()
并被setHeight()
调用(当您这样做时,您可能希望重新绘制画布)。
一种选择是定义一个自定义区域来保存画布,并覆盖其layoutChildren()
方法来调整画布大小和重新绘制画布。这可能看起来像:
public class CanvasPane extends Region {
private final Canvas canvas ;
private Consumer<Canvas> repaint ;
public CanvasPane() {
this.canvas = new Canvas() ;
getChildren().add(canvas);
repaint = c -> {} ;
}
public Consumer<Canvas> getRepaint() {
return repaint;
}
public void setRepaint(Consumer<Canvas> repaint) {
this.repaint = repaint ;
}
public Canvas getCanvas() {
return canvas ;
}
@Override
protected void layoutChildren() {
super.layoutChildren();
double width = getWidth();
canvas.setWidth(width);
double height = getHeight();
canvas.setHeight(height);
repaint.accept(canvas);
}
}
现在在 FXML 中:
<BorderPane>
<center>
<CanvasPane fx:id="canvasPane" />
</center>
</BorderPane>
在控制器中:
public class Controller {
@FXML
private CanvasPane canvasPane ;
public void initialize() {
canvasPane.setRepaint(this::repaintCanvas);
}
private void repaintCanvas(Canvas canvas) {
// example canvas painting:
double width = canvas.getWidth() ;
double height = canvas.getHeight() ;
GraphicsContext graphics = canvas.getGraphicsContext2D();
graphics.setFill(Color.web("#868c8c"));
graphics.fillRect(0, 0, width, height);
graphics.setFill(Color.web("#08cd4f"));
graphics.fillRect(20, 20, width-40, height-40);
}
}
现在,当边框窗格调整大小时,它将为CanvasPane
(即 a Region
)分配适当的空间。该layoutChildren()
方法将被自动调用,并且画布将被调整为其区域的大小(并重新绘制,如果您repaint
在控制器中提供 a)。
推荐阅读
- barcode - 使用 ZPL 打印代码 39 时跳过特殊字符
- syntax-error - 使用 microbit 在 mu 上编码时出现语法错误
- python - 有谁知道在这个错误中该怎么做?它是为了我的自学编程技能\
- machine-learning - 在 keras 中更新权重的问题
- c# - 使 Square Checkout URL 无效
- r - 删除r中的空文件夹
- active-directory - 在 Windows Server 2012 上创建 LDAP 服务器
- linux - 如何使用bash打印具有由“n”个字符组成的字符串的列字段的内容?
- google-colaboratory - 在 Tensorflow 2.0 中,如何使用 Google Colab TPU 将检查点保存到 Google Cloud Storage?
- docker - 使用 traefik(v2) 路由器在特定端口上请求转发