我如何动态地添加javaFX形状通过其控制器类共享窗格?



我正在创建一个应用程序,该应用程序需要显示由节点和边组成的图形。每个节点由一个Circle对象表示,每个边为一条Line。

我在应用程序中有多个场景,但图形需要在多个这些场景中显示。所以,我使用场景生成器创建了一个fxml文件,它只包含一个锚面板,我希望能够在锚面板上显示我的图形。我已经在其他需要显示图形的场景中包含了这个fxml文件,这样我就可以使用一个控制器将图形添加到单个锚窗格中,该锚窗格将在许多场景中共享。

但是,当我使用控制器将圆和线作为子控件添加到锚窗格时,它们是不可见的。使用调试工具,我可以看到它们确实是锚窗格的子窗格,但是它们没有显示出来。我可以看到我使用场景构建器添加到锚窗格的对象(例如,我使用场景构建器向锚窗格添加一个圆圈,当运行我的GUI时我可以看到,但没有其他我通过代码添加的子对象)。

为了缩小问题的范围,我尝试创建一个圆圈,并通过控制器类将其添加到锚窗格。尽管是锚窗格的子窗格,但是在运行GUI时,这个圆圈是不可见的。

GraphPaneController.java

public class GraphPaneController {
@FXML Pane paneGraph;
public void addCircle() {

Circle circle = new Circle();
circle.setFill(Color.RED);
circle.setRadius(50);
circle.setCenterX(0);
circle.setCenterY(0);

paneGraph.getChildren().add(circle);
}
}

MainMenuController.java

public class MainMenuController {
public void startButtonClicked() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("graph_pane.fxml"));
Parent root = loader.load();
GraphPaneController gpController = loader.getController();
controller.addCircle();
Frontend.setRoot("gamemode_select");
}
}

Frontend.java

public class Frontend extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage mainStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("mainmenu.fxml"));
Scene scene = new Scene(root, 600, 400);
mainStage.setScene(scene);
mainStage.show();
}

public static void setRoot(String fxml) throws IOException {
newScene.setRoot(loadFXML(fxml));
}
public static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Frontend.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
}

mainmenu.fxml

<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="graphvis.group30.MainMenuController">
<children>
<AnchorPane id="ap" maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<ImageView fitHeight="400.0" fitWidth="640.0" opacity="0.19" pickOnBounds="true" />
<Label layoutX="198.0" layoutY="112.0" text="Graph Colouring Game">
<font>
<Font size="24.0" />
</font>
</Label>
<Button id="btnInputGraphFromFile" layoutX="255.0" layoutY="200.0" mnemonicParsing="false" onAction="#btnInputGraphFromFileClicked" prefHeight="25.0" prefWidth="130.0" text="Input graph from file" />
<Button id="btnCreateRandomGraph" layoutX="255.0" layoutY="235.0" mnemonicParsing="false" onAction="#btnCreateRandomGraphClicked" text="Create random graph" />
<Label layoutX="197.0" layoutY="138.0" prefHeight="61.0" prefWidth="245.0" text="Made by Nathan Macdonald, Kasper van der Horst, Oguz Kagan Yarim, Miriam Espinosa, Dorina Sili" textAlignment="CENTER" wrapText="true">
<font>
<Font size="10.0" />
</font>
</Label>
<Button layoutX="255.0" layoutY="269.0" mnemonicParsing="false" onAction="#btnQuitClicked" prefHeight="25.0" prefWidth="130.0" text="Quit" />
</children>
</AnchorPane>
</children>
</VBox>

graph_pane.fxml

<AnchorPane fx:id="paneGraph" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="graphvis.group30.GraphPaneController" />

gamemode_select.fxml

<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="graphvis.group30.GamemodeSelectController">
<children>
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<fx:include source="graph_pane.fxml" />
<Label layoutX="139.0" layoutY="14.0" prefHeight="63.0" prefWidth="159.0" text="Select Gamemode:" wrapText="true">
<font>
<Font size="18.0" />
</font>
</Label>
<Button fx:id="btnGamemode1" layoutX="299.0" layoutY="33.0" mnemonicParsing="false" onAction="#btnGamemode1Clicked" text="untill death" />
<Button fx:id="btnGamemode2" layoutX="384.0" layoutY="33.0" mnemonicParsing="false" onAction="#btnGamemode2Clicked" text="timed" />
<Button fx:id="btnGamemode3" layoutX="440.0" layoutY="33.0" mnemonicParsing="false" onAction="#btnGamemode3Clicked" text="random " />
<Button fx:id="btnBack" layoutX="14.0" layoutY="360.0" mnemonicParsing="false" onAction="#btnBackClicked" text="back" />
</children>
</AnchorPane>
</children>
</VBox>

当查看游戏模式选择屏幕时,我希望看到我通过GraphPaneController添加到图形窗格中的圆圈,但它不在那里。我该怎么做才能将可视组件添加到跨多个场景共享的窗格中?

所以我通过为图创建一个模型类(GraphModel)和一个查看器类(GraphView)来实现这一点。模型类负责创建顶点和边,查看器类负责显示图形。

GraphView扩展了javafx.scene.layout.Pane,包含了一个AnchorPane属性,包含了要显示的图形元素,这些元素可以通过调用GraphView对象上的getAnchorPane方法添加到场景中。

最新更新