2015-09-16 50 views
0

因此,我遵循this blog(特别是part 2)创建自定义控件并将其导入Scene Builder。将setOnAction方法添加到自定义场景构建器控件

这是什么样子:

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方法,该方法将工作?

回答

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"; 
     } 
    }; 

而且,只要有事,你想要的操作事件被解雇,调用方法fireEvent(new ActionEvent());会为你做到这一点。这方法返回到继承此类的节点类,因为它扩展了AnchorPane(继承了节点的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 
     }); 

像往常一样赶在我项目。

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> 
+0

感谢您的回答,我确实查看了ButtonBase,但不明白事件是如何触发的。原来这是来自Node的fireEvent。我会发布自己的答案,因为我找到了一种方法使其工作,感谢您的帮助,非常感谢! – Maverick283

+0

@ Maverick283是的,你需要从节点调用一个方法。SimpleEventHandlerProperty使这更容易,因为您不需要实现自定义属性子类。 – Puce

+0

你在那里做了什么看起来相当不错!我认为尽管现在我的解决方案可以达到我的目的,但是感谢分享。 – Maverick283

相关问题