JavaFx自定义设计按钮在已用应用程序中单击检测

JavaFx自定义设计按钮在已用应用程序中单击检测,java,javafx,javafx-2,Java,Javafx,Javafx 2,使用带有两个文件CustomToggleSwitch.FXML和CustomToggleSwitch.java的FXML创建自定义设计 CustomToggleSwitch.fxml包含以下代码 <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?> <?import javafx.scene.shape.*?> <?import java.lang.*?>

使用带有两个文件CustomToggleSwitch.FXML和CustomToggleSwitch.java的FXML创建自定义设计

CustomToggleSwitch.fxml包含以下代码

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<fx:root type="Pane" xmlns="http://javafx.com/javafx/8"   xmlns:fx="http://javafx.com/fxml/1">
 <children>
    <Button mnemonicParsing="false" onAction="#click" text="Button" />
 </children>
</fx:root>
从这些创建jar文件,并在应用程序项目中使用该jar文件。应用程序具有test.fxml:

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

<?import com.custom.*?>
<?import com.custom.CustomToggleSwitch?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-   Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0"   xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
  <children>
    <CustomToggleSwitch layoutX="29.0" layoutY="48.0" />
  </children>
</AnchorPane>
按钮在GUI上成功显示,并检测到按钮点击。按钮在输出控制台上显示0、1、2、3..等。但测试结果并没有印在屏幕上

如何检测应用程序控制器类中的按钮按下?有人能帮我解决这个问题吗


非常感谢大家。

之所以发生这种情况,是因为CustomToggleSwitch.fxml中声明了
onAction=“#click”
,因此
FXMLLoader
将在CustomToggleSwitch.java中查找
click()

TestController
类中添加
click()
不会有任何作用,因为在test.fxml中没有任何节点具有
onAction=“#click”

CustomToggleSwitch中的
按钮
TestController
类通信的一种方法是将事件中继出去

public class CustomToggleSwitch extends Pane {
    // Same stuff

    private List<Runnable> onClickRunnables = new ArrayList<>();

    public final void addButtonOnClickRunnable(Runnable runnable) {
        Objects.requireNonNull(runnable);
        onClickRunnables.add(runnable);
    }

    @FXML 
    private void click(ActionEvent actionEvent){
        System.out.println(tick++);
        if (!onClickRunnables.isEmpty()) {
            onClickRunnables.forEach(r -> r.run());
        }
    }
}


public class TestController implements Initializable {
    // Give CustomToggleSwitch control an fx:id in FXML
    @FXML private CustomToggleSwitch customSwitch;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        customSwitch.addButtonOnClickRunnable(this::click);
    }
}
公共类CustomToggleSwitch扩展窗格{
//同样的东西
private List onClickRunnables=new ArrayList();
公共最终作废AddButtonNonClickRunnable(Runnable-Runnable){
对象。requirennull(可运行);
onClickRunnables.add(runnable);
}
@FXML
私有作废点击(ActionEvent ActionEvent){
System.out.println(tick++);
如果(!onClickRunnables.isEmpty()){
onClickRunnables.forEach(r->r.run());
}
}
}
公共类TestController实现了可初始化{
//在FXML中为CustomToggleSwitch控件指定一个fx:id
@FXML私有CustomToggleSwitch customSwitch;
@凌驾
公共void初始化(URL arg0,ResourceBundle arg1){
customSwitch.addButtonClickRunnable(this::click);
}
}

另一种方法是在
CustomToggleSwitch
out中显示
按钮。就个人而言,我建议不要这样做,因为隐藏“控件”的实现更为整洁。

发生这种情况是因为
onAction=“#click”
在CustomToggleSwitch.fxml中声明,因此
fxmloader
将在CustomToggleSwitch.java中查找
click()

TestController
类中添加
click()
不会有任何作用,因为在test.fxml中没有任何节点具有
onAction=“#click”

CustomToggleSwitch中的
按钮
TestController
类通信的一种方法是将事件中继出去

public class CustomToggleSwitch extends Pane {
    // Same stuff

    private List<Runnable> onClickRunnables = new ArrayList<>();

    public final void addButtonOnClickRunnable(Runnable runnable) {
        Objects.requireNonNull(runnable);
        onClickRunnables.add(runnable);
    }

    @FXML 
    private void click(ActionEvent actionEvent){
        System.out.println(tick++);
        if (!onClickRunnables.isEmpty()) {
            onClickRunnables.forEach(r -> r.run());
        }
    }
}


public class TestController implements Initializable {
    // Give CustomToggleSwitch control an fx:id in FXML
    @FXML private CustomToggleSwitch customSwitch;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        customSwitch.addButtonOnClickRunnable(this::click);
    }
}
公共类CustomToggleSwitch扩展窗格{
//同样的东西
private List onClickRunnables=new ArrayList();
公共最终作废AddButtonNonClickRunnable(Runnable-Runnable){
对象。requirennull(可运行);
onClickRunnables.add(runnable);
}
@FXML
私有作废点击(ActionEvent ActionEvent){
System.out.println(tick++);
如果(!onClickRunnables.isEmpty()){
onClickRunnables.forEach(r->r.run());
}
}
}
公共类TestController实现了可初始化{
//在FXML中为CustomToggleSwitch控件指定一个fx:id
@FXML私有CustomToggleSwitch customSwitch;
@凌驾
公共void初始化(URL arg0,ResourceBundle arg1){
customSwitch.addButtonClickRunnable(this::click);
}
}
另一种方法是在
CustomToggleSwitch
out中显示
按钮。就我个人而言,我建议不要这样做,因为隐藏“控制”的实现更为整洁


在组件中添加带有getter和setter的侦听器属性 控制器

Jai的示例是正确的,但与javafx的其他组件不一致。为了正确实现,可以使用可以在FXML和手动模式下操作的属性

这是添加了onMyAction属性的用户组件控制器。此属性用于事件通知

public class CustomToggleSwitch extends Pane {

    private ObjectProperty<EventHandler<ActionEvent>> onMyAction = new SimpleObjectProperty<EventHandler<ActionEvent>>();

    public CustomToggleSwitch() {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
        loader.setRoot(this);
        loader.setController(this);

        try {
            loader.load();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    @FXML
    private void initialize() {

    }

    @FXML
    private void click(ActionEvent event) {
        if(onMyAction.get() != null) {
            onMyAction.get().handle(event);
        }
    }

    public EventHandler<ActionEvent> getOnMyAction() {
        return onMyAction.get();
    }

    public ObjectProperty<EventHandler<ActionEvent>> onMyActionProperty() {
        return onMyAction;
    }

    public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
        this.onMyAction.set(onMyAction);
    }
}
或者手动

<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
    <CustomToggleSwitch fx:id="customToggleSwitch"/>
</AnchorPane>

更新


您不需要使用属性。使getter和setter可用应该足以从fxml使用它。(我还没有遇到将listerner添加到事件处理程序属性的情况。)

这是一种不使用属性的转换

public class CustomToggleSwitch extends Pane {

    private EventHandler<ActionEvent> myEventHandler;

    public CustomToggleSwitch() {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
        loader.setRoot(this);
        loader.setController(this);

        try {
            loader.load();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    @FXML
    private void initialize() {

    }

    @FXML
    private void click(ActionEvent event) {
        if(myEventHandler != null) {
            myEventHandler.handle(event);
        }
    }

    public EventHandler<ActionEvent> getOnMyAction() {
        return myEventHandler;
    }

    public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
        myEventHandler = onMyAction;
    }
}
公共类CustomToggleSwitch扩展窗格{
私有事件处理程序myEventHandler;
公共CustomToggleSwitch(){
FXMLLoader=新的FXMLLoader();
setLocation(getClass().getResource(“/sample/CustomToggleSwitch.fxml”);
setRoot(this);
loader.setController(此);
试一试{
loader.load();
}
捕获(IOE异常){
e、 printStackTrace();
}
}
@FXML
私有void初始化(){
}
@FXML
私有无效单击(ActionEvent事件){
如果(myEventHandler!=null){
myEventHandler.handle(事件);
}
}
public EventHandler getOnMyAction(){
返回myEventHandler;
}
公共void setOnMyAction(EventHandler onMyAction){
myEventHandler=onMyAction;
}
}

在组件中添加带有getter和setter的侦听器属性 控制器

Jai的示例是正确的,但与javafx的其他组件不一致。为了正确实现,可以使用可以在FXML和手动模式下操作的属性

这是添加了onMyAction属性的用户组件控制器。此属性用于事件通知

public class CustomToggleSwitch extends Pane {

    private ObjectProperty<EventHandler<ActionEvent>> onMyAction = new SimpleObjectProperty<EventHandler<ActionEvent>>();

    public CustomToggleSwitch() {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
        loader.setRoot(this);
        loader.setController(this);

        try {
            loader.load();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    @FXML
    private void initialize() {

    }

    @FXML
    private void click(ActionEvent event) {
        if(onMyAction.get() != null) {
            onMyAction.get().handle(event);
        }
    }

    public EventHandler<ActionEvent> getOnMyAction() {
        return onMyAction.get();
    }

    public ObjectProperty<EventHandler<ActionEvent>> onMyActionProperty() {
        return onMyAction;
    }

    public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
        this.onMyAction.set(onMyAction);
    }
}
或者手动

<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
    <CustomToggleSwitch fx:id="customToggleSwitch"/>
</AnchorPane>

更新


您不需要使用属性。使getter和setter可用应该足以从fxml使用它。(我没有遇到将listerner添加到事件h的情况
public class Controller {

    @FXML
    private CustomToggleSwitch customToggleSwitch;

    @FXML
    private void initialize() {
        customToggleSwitch.setOnMyAction(event -> {

        });
    }

}
public class CustomToggleSwitch extends Pane {

    private EventHandler<ActionEvent> myEventHandler;

    public CustomToggleSwitch() {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
        loader.setRoot(this);
        loader.setController(this);

        try {
            loader.load();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    @FXML
    private void initialize() {

    }

    @FXML
    private void click(ActionEvent event) {
        if(myEventHandler != null) {
            myEventHandler.handle(event);
        }
    }

    public EventHandler<ActionEvent> getOnMyAction() {
        return myEventHandler;
    }

    public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
        myEventHandler = onMyAction;
    }
}