自定义组件 JavaFX 的自定义动作发射器 属性 - 怎么样?

Custom action emitter property for custom component JavaFX - How?

在开发 JavaFX 应用程序项目的过程中,这是我第一个真正的笨蛋,我什至不知道如何正确地说出我想做的事情,因为我不知道我尝试使用的技术的名称。

在我的应用程序中,我有多个自定义组件,因此我可以构建更复杂的场景。本题涉及3个控制组件;一个 PrimaryControl 组件 (SplitPane),它包含一个 MenuComponent 和一个 ActivityComponent(都是自定义的),它们根据在 MenuComponent 中设置的单选按钮的选择而改变。

如何让 MenuControl class 到 "emit" 当 ToggleGroup(来自该组件)中的单选按钮发生更改时执行的操作,然后将由父级中的函数处理组件 PrimaryControl 以便它可以更改哪个 ActivityComponent 是 visible/active?忍耐一下。

primary_control.fxml

<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml">
    <MenuControl onToggleGroupButtonSelectionChanged="#onChange"/>
    <ActivityOneControl fx:id="one" isVisible="true"/>
    <ActivityTwoControl fx:id="two" isVisible="false"/>
    ...
</fx:root>

menu_control.fxml

<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/10.0.2-internal">

    <GridPane alignment="CENTER" hgap="10" vgap="10">
        <padding><Insets bottom="25" left="25" right="25" top="15" /></padding>
        <Label text="Select A Task" GridPane.columnIndex="0" GridPane.rowIndex="0">
            <font><Font name="System Bold" size="13.0" /></font>
        </Label>

        <fx:define>
            <ToggleGroup fx:id="menuSelection"/>
        </fx:define>

        <RadioButton fx:id="one" text="one" GridPane.columnIndex="0" GridPane.rowIndex="1" toggleGroup="$menuSelection">
        </RadioButton>
        <RadioButton fx:id="two" text="two" GridPane.columnIndex="0" GridPane.rowIndex="2" toggleGroup="$menuSelection">
        </RadioButton>
        <RadioButton fx:id="three" text="three" GridPane.columnIndex="0" GridPane.rowIndex="3" toggleGroup="$menuSelection">

        </RadioButton>
    </GridPane>

</fx:root>

如何在我的 MenuControl java class 中创建一个侦听器,它将能够检测到 ToggleGroup 选择更改,然后将该更改发送到 onToggleGroupButtonSelectionChanged="#onChange" 以便我可以处理从 PrimaryControl java class 选择按钮?我记得在 Angular 做过这种事情,这很容易,但出于某种原因,我找不到任何关于如何做到这一点的信息 Java。这就是所谓的依赖注入吗?

我发现了这个 link 并尝试解决我的问题但没有成功,因为没有任何解释并且正在为 JavaFX 2.0 - create action handler for custom component in FXML 侦听不同的事件。

PrimaryController.java(与MenuControl.java相同)

public class PrimaryControl extends VBox {

    public DashboardControl() {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("primary_control.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    @FXML
    protected void onChange() {
        System.out.println("change activity");
    }
}

提前感谢任何帮助我的人。

  • 首先,创建一个代表可能选择的枚举:
public enum SelectionMode {
    ONE, TWO, THREE
}
  • 现在,将 属性 添加到您的 Menu 控件,使其他控件能够知道选择了什么,而无需暴露其背后的逻辑或使其可从其他控件更改(使用 ReadOnlyObjectProperty) :
private ReadOnlyObjectWrapper<SelectionMode> selectionMode
    = new ReadOnlyObjectWrapper<>(this, "selectionMode");

public final ReadOnlyObjectProperty<SelectionMode> selectionModeProperty() {
    return selectionMode.getReadOnlyProperty();
}

private final SelectionMode getSelectionMode() {
    return selectionMode.get();
}
  • 将此 属性 绑定到菜单控制器 class 的 initialize 方法中选定的单选按钮。请注意,我使用的是 setUserDatagetUserData 方法,否则,您需要为每个单选按钮添加一个 if 子句:
@Override
public void initialize(URL location, ResourceBundle resources) {
    one.setUserData(SelectionMode.ONE);
    two.setUserData(SelectionMode.TWO);
    three.setUserData(SelectionMode.THREE);

    selectionMode.bind(Bindings.createObjectBinding(() -> {
        Toggle selectedToggle = menuSelection.getSelectedToggle();
        return (SelectionMode) selectedToggle.getUserData();
    }, menuSelection.selectedToggleProperty()));
}
  • 您的主控制器 class 可以通过在 <MenuControl fx:id="menu"/> 中设置一个 ID 来访问其菜单控制器。 然后你可以只分配一个 ChangeListener 并在每次更改选择时得到通知:
menu.selectionModeProperty().addListener((observable, oldValue, newValue) -> {
    // write your code here
});

注意:您可以像这样在您的 fxml 中初始化用户数据(而不是在 initialize 方法中这样做):

<RadioButton fx:id="one" text="one" toggleGroup="$menuSelection">
    <userData>
        <SelectionMode fx:constant="ONE"/>
    </userData>
</RadioButton>
<RadioButton fx:id="two" text="two" toggleGroup="$menuSelection">
    <userData>
        <SelectionMode fx:constant="TWO"/>
    </userData>
</RadioButton>
<RadioButton fx:id="three" text="three" toggleGroup="$menuSelection">
    <userData>
        <SelectionMode fx:constant="THREE"/>
    </userData>
</RadioButton>