Javafx:从组件本身中删除组件

发布于 2025-02-07 08:59:50 字数 3903 浏览 2 评论 0 原文

我有一个带有主控制器的简单Javafx应用程序。在此主控制器中,我动态添加了此组件:

添加的组件:

“添加组件”

fxml代码(paramvalue.fxml):

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>

<HBox alignment="CENTER" prefHeight="40.0" prefWidth="833.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demoSpreadsSheet.ParamValueController">
   <children>
      <Label prefHeight="95.0" prefWidth="83.0" text="Paramètre : " />
      <TextField fx:id="paramName" prefHeight="32.0" prefWidth="300.0" />
      <Label prefHeight="95.0" prefWidth="83.0" text="Valeur : ">
         <HBox.margin>
            <Insets left="40.0" />
         </HBox.margin>
      </Label>
      <TextField fx:id="paramValue" prefHeight="32.0" prefWidth="300.0" />
      <Button mnemonicParsing="false" prefHeight="25.0" prefWidth="12.0">
         <HBox.margin>
            <Insets left="20.0" />
         </HBox.margin>
         <graphic>
            <ImageView fitHeight="26.0" fitWidth="21.0" onMouseClicked="#openSpreadSheet" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@../../Images/spreadsheet.png" />
               </image>
            </ImageView>
         </graphic>
      </Button>
      <Button mnemonicParsing="false" onAction="#removeParamValue" prefHeight="25.0" prefWidth="12.0">
         <graphic>
            <ImageView fitHeight="26.0" fitWidth="21.0" onMouseClicked="#openSpreadSheet" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@../../Images/remove.png" />
               </image>
            </ImageView>
         </graphic>
         <HBox.margin>
            <Insets left="10.0" />
         </HBox.margin>
      </Button>
   </children>
</HBox>

组件的控制器:

package com.example.demoSpreadsSheet;

import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;

public class ParamValueController extends HBox {

    @FXML TextField paramName, paramValue;

    public ParamValueController() {}

    @FXML
    public void openSpreadSheet(){

    }

    @FXML
    private void removeParamValue(){
        //I don't know if it's possible to remove it here
    }




}

我添加自定义组件的控制器:

package com.example.demoSpreadsSheet;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import java.io.IOException;

public class DoublonController extends BorderPane {

    @FXML VBox paramValueList;

    public DoublonController(){}

    @FXML
    public void initialize() throws IOException {
        paramValueList.getChildren().addAll(createParamValueComponent(), createParamValueComponent());
    }

    private HBox createParamValueComponent() throws IOException {
        FXMLLoader paramValueLoader = new FXMLLoader(DoublonController.class.getResource("paramValue.fxml"));
        return paramValueLoader.load();
    }

    @FXML
    private void addParamValue() throws IOException {
        this.paramValueList.getChildren().add(createParamValueComponent());
    }
}

当用户单击红十字时,我想删除此组件。问题在于,Redcross在我想删除的类中称之为“ RemoveParamValue()”函数,我认为这是不可能的。.

您有解决方法吗?

提前致谢。

I have a simple JavaFX application with main controller. In this main controller I dynamically add this component :

Added component:

Added component

FXML code of this component (paramValue.fxml) :

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>

<HBox alignment="CENTER" prefHeight="40.0" prefWidth="833.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demoSpreadsSheet.ParamValueController">
   <children>
      <Label prefHeight="95.0" prefWidth="83.0" text="Paramètre : " />
      <TextField fx:id="paramName" prefHeight="32.0" prefWidth="300.0" />
      <Label prefHeight="95.0" prefWidth="83.0" text="Valeur : ">
         <HBox.margin>
            <Insets left="40.0" />
         </HBox.margin>
      </Label>
      <TextField fx:id="paramValue" prefHeight="32.0" prefWidth="300.0" />
      <Button mnemonicParsing="false" prefHeight="25.0" prefWidth="12.0">
         <HBox.margin>
            <Insets left="20.0" />
         </HBox.margin>
         <graphic>
            <ImageView fitHeight="26.0" fitWidth="21.0" onMouseClicked="#openSpreadSheet" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@../../Images/spreadsheet.png" />
               </image>
            </ImageView>
         </graphic>
      </Button>
      <Button mnemonicParsing="false" onAction="#removeParamValue" prefHeight="25.0" prefWidth="12.0">
         <graphic>
            <ImageView fitHeight="26.0" fitWidth="21.0" onMouseClicked="#openSpreadSheet" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@../../Images/remove.png" />
               </image>
            </ImageView>
         </graphic>
         <HBox.margin>
            <Insets left="10.0" />
         </HBox.margin>
      </Button>
   </children>
</HBox>

Controller of the component :

package com.example.demoSpreadsSheet;

import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;

public class ParamValueController extends HBox {

    @FXML TextField paramName, paramValue;

    public ParamValueController() {}

    @FXML
    public void openSpreadSheet(){

    }

    @FXML
    private void removeParamValue(){
        //I don't know if it's possible to remove it here
    }




}

The controller where I add my custom component :

package com.example.demoSpreadsSheet;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import java.io.IOException;

public class DoublonController extends BorderPane {

    @FXML VBox paramValueList;

    public DoublonController(){}

    @FXML
    public void initialize() throws IOException {
        paramValueList.getChildren().addAll(createParamValueComponent(), createParamValueComponent());
    }

    private HBox createParamValueComponent() throws IOException {
        FXMLLoader paramValueLoader = new FXMLLoader(DoublonController.class.getResource("paramValue.fxml"));
        return paramValueLoader.load();
    }

    @FXML
    private void addParamValue() throws IOException {
        this.paramValueList.getChildren().add(createParamValueComponent());
    }
}

I want to remove this component when the user click on the red cross. The problem is that the redcross calls the function "removeParamValue()" within the class that I want to remove which i think is impossible..

Do you have a workaround ?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

葬花如无物 2025-02-14 08:59:50

您至少可以使用两种方法。


获取 parent

,如@kleopatra in 问题注释,您可以从“儿童”控制器内获取root fxml节点的父母,请检查它是否是 pane pane 的实例,如果是的,则修改父母的子女列表。
例如:

@FXML
private void removeParamValue() {
    var parent = container.getParent();
    if (parent instanceof Pane pane) {
        pane.getChildren().remove(container);
    }
}

这要求您将根FXML元素注入控制器。我将字段的名称 container ,其类型为 hbox ,但是您可以将其命名为任何您想要的任何东西(只需确保添加相应的 fx :id 属性属于FXML文件)。我还使用 实例>实例 的模式匹配,该在Java中最终确定16。如果您至少不使用Java 16,则需要手动施放 parent pane

代码

注释的问题您无法使用 this.getParent(),因为控制器本身从未添加到场景图中。实际上,使用您的代码当前的编写方式,您的控制器类别不应扩展 hbox (我假设您的其他控制器类也存在类似的问题)。也许您打算使用 ,但这涉及更改FXML文件的根元素以及如何加载FXML文件。阅读

换句话说,除非您要使用 fx:root ,否则 扩展了Hbox 和从您的控制器类中扩展了BorderPane


使用“回调”的

另一种方法是使用回调。将方法添加到您的 paramvaluecontroller 接受某些功能接口(例如,运行):

public void setOnRemove(Runnable action) {
    // also declare a field to store the Runnable in
    this.action = action;
}

然后您的“删除param值”方法看起来像:

@FXML
private void removeParamValue() {
    if (action != null) {
        action.run();
    }
}

并且您要修改代码这样可以加载“孩子”的FXML:

private HBox createParamValueComponent() throws IOException {
    FXMLLoader paramValueLoader = new FXMLLoader(DoublonController.class.getResource("paramValue.fxml"));
    HBox root = paramValueLoader.load();
    
    // invoked *after* you load the FXML file
    ParamValueController controller = paramValueLoader.getController();
    controller.setOnRemove(() -> paramValueList.getChildren().remove(root));

    return root;
}

就个人而言,我更喜欢这种方法更安全,更灵活,并且我认为更清楚。但这也比第一种方法更多。

There are at least two approaches you can use.


Get the Parent

As mentioned by @kleopatra in a question comment, you can get the parent of the root FXML node from within the "child" controller, check if it is an instance of Pane and, if it is, then modify the parent's children list.
For example:

@FXML
private void removeParamValue() {
    var parent = container.getParent();
    if (parent instanceof Pane pane) {
        pane.getChildren().remove(container);
    }
}

This requires you to inject the root FXML element into the controller. I made the name of the field container, whose type would be HBox, but you can name it anything you'd like (just make sure add the corresponding fx:id attribute to the FXML file). I also made use of pattern matching for instanceof, which was finalized in Java 16. If you are not using at least Java 16, then you'll need to manually cast parent to a Pane.

Problem With Your Code

Note you can't use this.getParent(), because the controller itself has never been added to the scene graph. In fact, with how your code is currently written, your controller class should not be extending HBox at all (and I assume a similar problem with your other controller class). Perhaps you meant to use fx:root, but that would involve changing both the root element of your FXML file and how you load the FXML file. Read the linked documentation for more information.

In other words, unless you want to use fx:root, remove the extends HBox and extends BorderPane from your controller classes.


Use a "Callback"

The other approach is to use a callback. Add a method to your ParamValueController which accepts some functional interface (e.g., Runnable):

public void setOnRemove(Runnable action) {
    // also declare a field to store the Runnable in
    this.action = action;
}

Then your "remove param value" method would look like:

@FXML
private void removeParamValue() {
    if (action != null) {
        action.run();
    }
}

And you'd modify the code that loads the "child" FXML like so:

private HBox createParamValueComponent() throws IOException {
    FXMLLoader paramValueLoader = new FXMLLoader(DoublonController.class.getResource("paramValue.fxml"));
    HBox root = paramValueLoader.load();
    
    // invoked *after* you load the FXML file
    ParamValueController controller = paramValueLoader.getController();
    controller.setOnRemove(() -> paramValueList.getChildren().remove(root));

    return root;
}

Personally, I prefer this approach as it's safer, more flexible, and in my opinion clearer. But it is also more work than the first approach.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文