2015-09-16 71 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

相關問題