将setOnAction方法添加到自定义Scene Builder Control

时间:2015-09-16 07:24:27

标签: javafx scenebuilder

所以我跟着this blog(特别是part 2)来创建自定义控件并将其导入到Scene Builder中。

这就是它的样子:

Custom control that holds a ArrayList

这是fxml文件:

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="30.0" prefWidth="150.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <HBox alignment="CENTER" layoutX="-65.0" layoutY="-56.0" spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <Button fx:id="previousButton" minWidth="25.0" mnemonicParsing="false" prefWidth="25.0" text="&lt;" />
            <Label fx:id="label" alignment="CENTER" contentDisplay="CENTER" prefWidth="500.0" text="Label" />
            <Button fx:id="nextButton" minWidth="25.0" mnemonicParsing="false" prefWidth="25.0" text="&gt;" />
         </children>
      </HBox>
   </children>
</fx:root>

这是类文件:

package swipeselector;

import java.io.IOException;
import java.util.ArrayList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;

/**
 *
 * @author patrickb
 */
public class SwipeSelector extends AnchorPane {

    @FXML
    private Button previousButton;
    @FXML
    private Label label;
    @FXML
    private Button nextButton;

    ArrayList<String> items;
    int selectedIndex;
    private boolean repetitive;

    public SwipeSelector() {
        FXMLLoader fxmlLoader = new FXMLLoader(
                getClass().getResource("swipeSelectorFXML.fxml"));

        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

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

        items = new ArrayList<>();
        selectedIndex = 0;

        previousButton.setOnAction((ActionEvent event) -> {
            setPrevious();
        });

        nextButton.setOnAction((ActionEvent event) -> {
            setNext();
        });

    }

    public void setItems(ArrayList<String> items) {
        this.items = items;
        selectFirst();
    }

    public void setPrevious() {
        updateItem(selectedIndex - 1);
    }

    public void setNext() {
        updateItem(selectedIndex + 1);
    }

    public void selectFirst() {
        updateItem(0);
    }

    private void selectLast() {
        updateItem(items.size() - 1);
    }

    private void updateItem() {
        if (items.isEmpty()) {
            label.setText("");
        } else {
            if (selectedIndex < 0) {
                if (repetitive) {
                    selectedIndex = items.size() - 1;
                } else {
                    selectedIndex = 0;
                }
            }
            if (selectedIndex >= items.size()) {
                if (repetitive) {
                    selectedIndex = 0;
                } else {
                    selectedIndex = items.size() - 1;
                }
            }
            label.setText(items.get(selectedIndex));
        }
    }

    private void updateItem(int selectedIndex) {
        this.selectedIndex = selectedIndex;
        updateItem();
    }

    public void setRepetitive(boolean cyclesThrough) {
        this.repetitive = cyclesThrough;
    }

}

一切正常,但是:当我点击下一个或上一个按钮时,我希望在原始项目中发生一些事情。我通常会通过向对象添加setOnAction(new EventHandler ...方法来完成此操作。但是这个方法不存在,所以我不知何故需要将它添加到我的自定义控件中。 每次单击两个按钮中的一个时,如何让我的自定义控件调用ActionEvent,以及如何为我的对象创建一个setOnAction方法?

2 个答案:

答案 0 :(得分:1)

您需要创建自定义事件。不幸的是,关于这一点的信息很少。您可以查看ButtonBase的源代码以获取示例。

您需要定义onAction属性:

ObjectProperty<EventHandler<ActionEvent>> onAction

我为此实现了一个实用程序类:SimpleEventHandlerProperty

您可以在此处使用SimpleEventHandlerProperty找到完整的示例:LeftTestPane.java

您可以从Maven Central获取图书馆:

<dependency>
    <groupId>org.drombler.commons</groupId>
    <artifactId>drombler-commons-fx-core</artifactId>
    <version>0.6</version>
</dependency>

答案 1 :(得分:1)

我找到了让它发挥作用的方法。以下代码被添加到类文件中(它基本上是从ButtonBase复制的。

public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }
    public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); }
    public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); }
    private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<EventHandler<ActionEvent>>() {
        @Override protected void invalidated() {
            setEventHandler(ActionEvent.ACTION, get());
        }

        @Override
        public Object getBean() {
            return SwipeSelector.this;
        }

        @Override
        public String getName() {
            return "onAction";
        }
    };

此外,每当您希望触发Action Event的某些事情发生时,调用方法fireEvent(new ActionEvent());将为您执行此操作。此方法返回到Node类,它继承到此类,因为它扩展了AnchorPane(从Node继承了fireEvent方法)。

所以在我的情况下,我用这两个按钮替换了我的两个onAction方法:

previousButton.setOnAction((ActionEvent event) -> {
            setPrevious();
            fireEvent(event);
        });

nextButton.setOnAction((ActionEvent event) -> {
            setNext();
            fireEvent(event);
        });

现在,每当按下两个按钮中的一个时,就会触发一个ActionEvent(我刚刚为此目的传递了按钮事件),我可以通过添加

在我的项目中捕获它
swipeSelector.setOnAction((ActionEvent event) -> {
            System.out.println("Event fired!!!");
            //DO SOMETHING 
        });
像往常一样。