2016-04-14 81 views
1

我有多個控制器,每個控制器都關聯到一個不同的FXML文件。在一個節點中有一個事件需要跨其他節點進行同步,因此我決定在另一個事件中執行此操作,並在各個控制器文件中執行事件處理程序。有沒有從靜態方法調用類方法的「最佳」方式?

要註冊的事件處理程序需要事件處理方法是靜態的(即addEventHandler(SomeEvent, ClassName::MethodName)

因此,控制器看起來像......

public class MyController { 
    private static MyController selfRef = null; 

    public MyController() { 
     selfRef = this; 
    } 

    public static void someEventHandler(Event event) { 
     if (selfRef != null) { 
      selfRef.doSomethingUseful(); 
     } 
    } 

    private void doSomethingUseful() { /* synch the nodes */ } 
} 

這工作,但似乎有點是否有一個首選的機制來實現相同的最終結果?

+0

它看起來python-y,但嘿,如果它的工作原理 – Norsk

+0

猜你只需要使單身人士 –

+1

你有沒有考慮過Google Guava EventBus?它看起來很適合你的需求。 – vl4d1m1r4

回答

2

你可能有更多的靈活性,這一點,如果你擺脫所有靜態的東西,使事件處理您的控制器類的成員,如下所示。

樣品實現無靜態成員

import javafx.event.*; 
import javafx.fxml.*; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.stage.*; 

import java.io.IOException; 

class CustomerDialogController { 
    @FXML 
    private Label customerName; 

    private EventHandler<Event> customEventHandler = event -> { 
     // handle the event... 
    }; 

    void initData(Customer customer) { 
     customerName.setText(customer.getName()); 
    } 

    public EventHandler<Event> getCustomEventHandler() { 
     return customEventHandler; 
    } 
} 

public class EventHandling { 
    public Stage showCustomerDialog(Customer customer) throws IOException { 
     FXMLLoader loader = new FXMLLoader(getClass().getResource("customerDialog.fxml")); 

     Stage stage = new Stage(StageStyle.DECORATED); 
     stage.setScene(new Scene(loader.load())); 

     CustomerDialogController controller = loader.getController(); 
     controller.initData(customer); 

     stage.addEventHandler(Event.ANY, controller.getCustomEventHandler()); 
     stage.show(); 

     return stage; 
    }  
} 

class Customer { 
    private String name; 

    Customer(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 
} 

注意事項實施方案

在事件處理程序已被添加到舞臺上的例子,但它同樣可以被添加到任何場景或節點或任何能夠處理事件的功能。

如果需要,還可以爲事件處理程序添加setter以允許從外部更改事件處理邏輯。

除了上面的設置,您可能希望讓控制器在其初始化方法中自行註冊事件處理程序。無論您是否這樣做,取決於您是否希望能夠註冊暴露在控制器之外的事件處理程序,或者是否希望使用封裝來隱藏控制器本地的所有事件處理邏輯。上(也許是上級)的替代品

作爲一種替代方法,而不是使用事件中的JavaFX處理系統爲您定製的方法

注意,你可以使用第三方系統如Google Guava Event Bus

您還應該考慮爲什麼您需要將自定義事件處理添加到您的應用程序。 JavaFX支持非常靈活的綁定和觀察者模式。通過將模型對象的屬性公開爲可觀察的,通常不需要定製事件。通常,視圖控制器可以觀察對相關模型對象的任何更改,並根據UI交互來修改模型對象的內部狀態。如果您引入基於依賴注入的系統以將模型注入您的控制器,例如Guice,Spring,afterburner.fxGluon Ignite,則尤其如此。

1

也許你可以使用某種註冊表,它負責同步。下面是一個快速和骯髒的例子:

public class Synchronizer { 

      private ObservableList<Node> nodes; 
      private boolean    isSyncing; 

      public Synchronizer() { 
       nodes = FXCollections.observableArrayList(); 
      } 

      public void addNode(Node node) { 
       nodes.add(node); 
      } 

      public void sync(Node sourceNode, Event event) { 
       if (isSyncing) { 
        return; 
       } 

       isSyncing = true; 
       for (Node node : nodes) { 
        if (node != sourceNode) { 
         node.fireEvent(event); 
        } 
       } 
       isSyncing = false; 
      } 
     } 

在您的控制器中,您可以將您想要同步的事件添加到同步器,並在eventListener中調用sync()

public class Controller { 

     private StackPane root; 
     private Button button; 

     public Controller(Synchronizer synchronizer) { 
      button = new Button(); 
      button.setOnAction(evt -> { 
       synchronizer.sync(button, evt); 
       //action 
      }); 
      synchronizer.addNode(button); 

      root = new StackPane(button); 
     } 
} 

編輯:

這應該爲一個更清潔的版本:

public class Starter extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     ViewController controller1 = new ViewController(); 
     ViewController controller2 = new ViewController(); 

     Synchronizer synchronizer = new Synchronizer(); 
     synchronizer.add(controller1); 
     synchronizer.add(controller2); 

     VBox box = new VBox(controller1.root, controller2.root); 
     primaryStage.setScene(new Scene(box)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

    public interface SyncTarget { 

     Node getSyncNode(); 

     void triggerAction(); 

    } 

public class Synchronizer { 

    private ObservableList<SyncTarget> syncTargets; 

    private EventHandler<Event>  eventHandler; 

    public Synchronizer() { 
     syncTargets = FXCollections.observableArrayList(); 
     eventHandler = e -> sync(); 

    } 

    public void add(SyncTarget target) { 
     syncTargets.add(target); 
     target.getSyncNode().addEventHandler(ActionEvent.ANY, eventHandler); 
    } 

    public void remove(SyncTarget target) { 
     syncTargets.remove(target); 
     target.getSyncNode().removeEventHandler(ActionEvent.ANY, eventHandler); 
    } 

    public void sync() { 
     for (SyncTarget target : syncTargets) { 
      target.triggerAction(); 
     } 
    } 
} 


    public class ViewController implements SyncTarget { 

     private StackPane root; 
     private Button button; 

     public ViewController() { 
      button = new Button(); 
      root = new StackPane(button); 
     } 

     @Override 
     public Node getSyncNode() { 
      return button; 
     } 


     @Override 
     public void triggerAction() { 
      //action 
     } 
    } 
} 
+0

「...通過將模型對象的屬性公開爲可觀察的,通常不需要定製事件。通常,視圖控制器可以觀察對相關模型對象的任何更改,並根據UI交互來修改模型對象的內部狀態。「 我喜歡這個選項。我不是一個真正的圖形用戶界面的人,這很適合我所熟悉的開發風格。也許如果我做更多的GUI,那麼我會深入JavaFX,但我喜歡從底層模型驅動所有控制器行爲的概念。 – SoCal

相關問題