2016-04-14 11 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; 
    } 
} 

ノート

なし

サンプル実装イベントハンドラがステージに追加されましたが、それは同様にいずれにも追加されている可能性の例ではシーンまたはノード、またはイベントを処理する能力を持つもの。

イベントハンドラのセッターを追加して、外部でイベント処理ロジックを変更できるようにすることもできます。

上記の設定に加えて、コントローラーにイベントハンドラーを初期化メソッドで自己登録させたい場合があります。そうするかどうかは、コントローラーの外部に公開されたイベントハンドラーを登録するかどうか、またはカプセル化を使用してコントローラーのローカルのすべてのイベント処理ロジックを非表示にするかどうかによって異なります。むしろ、カスタムアプローチのための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; 
      } 
     } 

あなたはシンクロナイザに、そのイベントあなたが同期取得したいノードを追加し、イベントリスナーで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); 
     } 
} 

EDIT:

これは、クリーンバージョンのために作る必要があります:あなたはすべての静的なものを取り除く場合はこれでより多くの柔軟性を持っているし、イベントを作るかもしれない

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の人ではなく、これは私が快適な開発スタイルにはるかによく合います。たぶん、もっとGUIを作れば、JavaFXについてもっと深く理解することができますが、基本モデルからすべてのコントローラの動作を駆動するという概念が気に入っています。 – SoCal

関連する問題