2016-04-28 8 views
0

JavaFXでコンテキストメニューを生成し、クリックされたMenuItemまたはそれに関連するデータを機能的な方法で取得する方法はありますか?私のような何かをできるようにしたいと思います:機能パラダイムのJavaFX ContextMenu

MenuItem menuItem1 = new MenuItem("Item 1"); 
menuItem1.setUserData(1); 
MenuItem menuItem2 = new MenuItem("Item 2"); 
menuItem1.setUserData(2); 

ContextMenu menu = new ContextMenu(menuItem1, menuItem2); 
Integer result = menu.show(...) 

if (result == 1) 
    ... 
else if (result == 2) 
    ... 
else 
    ... 

をしかし、私の知る限り、result = menu.show()ラインをエミュレートする方法はありません。方法はありますか?私はこれをブロッキング/同期させたい。 JavaFXのようなイベントベースではありません。

答えて

0

だ、https://stackoverflow.com/a/27081164/2270967

のおかげでenterNestedEventLoopexitNestedEventLoop方法がcom.sunであるが、Java 9

の公開APIに slated for inclusionです
import com.sun.javafx.tk.Toolkit; 
import javafx.scene.Node; 
import javafx.scene.control.ContextMenu; 
import javafx.scene.control.MenuItem; 

public class FunctionalContextMenu extends ContextMenu { 

    /** 
    * Create a new FunctionalContextMenu initialized with the given items 
    * 
    * @param items the initial menu items 
    */ 
    public FunctionalContextMenu(MenuItem... items) { 
     super(items); 
    } 

    /** 
    * Shows the context menu and waits until the user clicks an item or 
    * otherwise closes the menu. See 
    * {@link #show(javafx.scene.Node, double, double)} for more details 
    * regarding the display of the menu. 
    * 
    * @param anchor 
    * @param screenX 
    * @param screenY 
    * @return the clicked menu item, or {@code null} if the menu was closed 
    * without selecting a menu item 
    */ 
    public MenuItem showAndWait(Node anchor, double screenX, double screenY) { 
     super.show(anchor, screenX, screenY); 

     Object lock = new Object(); 
     this.setOnAction(actionEvt -> Toolkit.getToolkit().exitNestedEventLoop(lock, actionEvt.getTarget())); 
     this.setOnAutoHide(autohideEvt -> Toolkit.getToolkit().exitNestedEventLoop(lock, null)); 
     super.show(anchor, screenX, screenY); 
     return (MenuItem) Toolkit.getToolkit().enterNestedEventLoop(lock); 
    } 
} 
2

あなたはソート缶です。警告は、そのようなメソッドはブロックされるため、バックグラウンドスレッドで実行する必要があります(これは少し醜いものになります)。ここで

は例です:私は終わったのはここ

import java.util.Optional; 
import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.atomic.AtomicReference; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.control.ContextMenu; 
import javafx.scene.control.MenuItem; 
import javafx.scene.layout.Pane; 
import javafx.stage.Stage; 

public class FunctionalContextMenu extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     Pane root = new Pane(); 
     ContextMenu menu = new ContextMenu(); 
     MenuItem item1 = new MenuItem("Item 1"); 
     MenuItem item2 = new MenuItem("Item 2"); 
     menu.getItems().addAll(item1, item2); 
     root.setOnContextMenuRequested(e -> { 
      showMenu(menu, root, e.getScreenX(), e.getScreenY()); 
     }); 

     Scene scene = new Scene(root, 400, 400); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private void showMenu(ContextMenu menu, Node anchor, double screenX, double screenY) { 
     new Thread(() -> 

      showAndWait(menu, anchor, screenX, screenY) 
      .ifPresent(item -> System.out.println("You chose "+item.getText())) 

     ).start(); 
    } 

    private Optional<MenuItem> showAndWait(ContextMenu menu, Node anchor, double screenX, double screenY) { 

     // executing this on the FX Application Thread would cause deadlock, 
     // so guard against it: 
     if (Platform.isFxApplicationThread()) { 
      throw new IllegalStateException("showAndWait cannot be called from the FX Application Thread"); 
     } 

     CountDownLatch latch = new CountDownLatch(1); 
     AtomicReference<MenuItem> selectedItem = new AtomicReference<>(); 
     Platform.runLater(() -> { 
      EventHandler<ActionEvent> handler = e -> selectedItem.set((MenuItem)e.getSource()); 
      menu.setOnHidden(e -> { 
       for (MenuItem item : menu.getItems()) { 
        item.removeEventHandler(ActionEvent.ACTION, handler); 
       } 
       latch.countDown(); 
      }); 
      for (MenuItem item : menu.getItems()) { 
       item.addEventHandler(ActionEvent.ACTION, handler); 
      } 
      menu.show(anchor, screenX, screenY); 
     }); 
     try { 
      latch.await(); 
     } catch (InterruptedException e) { 
      Thread.currentThread().interrupt(); 
     } 
     return Optional.ofNullable(selectedItem.get()); 
    } 

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

ありがとうございます! JavaFXのドキュメントを少し熟読して、私は[Task](http://docs.oracle.com/javafx/2/api/javafx/concurrent/Task.html)を使ってスレッドを完全に包むことができると思いますshowAndWait()。 –

関連する問題