将 setOnAction 方法添加到自定义场景生成器控件
Add setOnAction method to custom Scene Builder Control
所以我特别按照 this blog (part 2 创建了一个自定义控件并将其导入到 Scene Builder 中。
这是它的样子:
这是 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="<" />
<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=">" />
</children>
</HBox>
</children>
</fx:root>
这是 class 文件:
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 方法?
您需要创建一个自定义事件。不幸的是,关于这方面的信息很少。您可以查看 ButtonBase 的源代码以获取示例。
您需要定义一个 onAction 属性:
ObjectProperty<EventHandler<ActionEvent>> onAction
我为此实现了一个实用程序 class:SimpleEventHandlerProperty
您可以在此处找到使用 SimpleEventHandlerProperty 的完整示例:LeftTestPane.java
您可以从 Maven Central 获取库:
<dependency>
<groupId>org.drombler.commons</groupId>
<artifactId>drombler-commons-fx-core</artifactId>
<version>0.6</version>
</dependency>
我找到了让它工作的方法。下面的代码添加到Class文件中(基本上是从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";
}
};
此外,无论何时发生您希望触发该动作事件的事情,调用方法 fireEvent(new ActionEvent());
都会为您执行此操作。此方法返回到节点 Class,它继承到此 class,因为它扩展了 AnchorPane(它从节点继承了 fireEvent
方法)。
所以在我的例子中,我用这个替换了我拥有的两个按钮的两个 onAction 方法:
previousButton.setOnAction((ActionEvent event) -> {
setPrevious();
fireEvent(event);
});
nextButton.setOnAction((ActionEvent event) -> {
setNext();
fireEvent(event);
});
现在,无论何时按下两个按钮中的一个,都会触发一个 ActionEvent(为此我刚刚传递了 Buttons 事件),我可以通过添加
在我的项目中捕获它
swipeSelector.setOnAction((ActionEvent event) -> {
System.out.println("Event fired!!!");
//DO SOMETHING
});
像往常一样。
所以我特别按照 this blog (part 2 创建了一个自定义控件并将其导入到 Scene Builder 中。
这是它的样子:
这是 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="<" />
<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=">" />
</children>
</HBox>
</children>
</fx:root>
这是 class 文件:
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 方法?
您需要创建一个自定义事件。不幸的是,关于这方面的信息很少。您可以查看 ButtonBase 的源代码以获取示例。
您需要定义一个 onAction 属性:
ObjectProperty<EventHandler<ActionEvent>> onAction
我为此实现了一个实用程序 class:SimpleEventHandlerProperty
您可以在此处找到使用 SimpleEventHandlerProperty 的完整示例:LeftTestPane.java
您可以从 Maven Central 获取库:
<dependency>
<groupId>org.drombler.commons</groupId>
<artifactId>drombler-commons-fx-core</artifactId>
<version>0.6</version>
</dependency>
我找到了让它工作的方法。下面的代码添加到Class文件中(基本上是从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";
}
};
此外,无论何时发生您希望触发该动作事件的事情,调用方法 fireEvent(new ActionEvent());
都会为您执行此操作。此方法返回到节点 Class,它继承到此 class,因为它扩展了 AnchorPane(它从节点继承了 fireEvent
方法)。
所以在我的例子中,我用这个替换了我拥有的两个按钮的两个 onAction 方法:
previousButton.setOnAction((ActionEvent event) -> {
setPrevious();
fireEvent(event);
});
nextButton.setOnAction((ActionEvent event) -> {
setNext();
fireEvent(event);
});
现在,无论何时按下两个按钮中的一个,都会触发一个 ActionEvent(为此我刚刚传递了 Buttons 事件),我可以通过添加
在我的项目中捕获它swipeSelector.setOnAction((ActionEvent event) -> {
System.out.println("Event fired!!!");
//DO SOMETHING
});
像往常一样。