2016-12-01 8 views
3

私は非常に新しいJavaFXです。昨日学習を開始しました。ドキュメントを読んで1日中読んだり、何も学んだりできませんでした。JavaFXでのノード選択の実装方法

ここでは、円を作成する簡単なJavaFXアプリケーションを作成します。クリックすると、そのストロークがオレンジ色(何色か)に変わります。 unlicked(その円以外のものをクリック)で、ストロークが白く(何らかの色に)変わります。

ここに私の疑似コードこれまで私が持っていたものです。 円を作成し、イベント(重要)を処理する別のクラスを作成したいと思います。

public class Something extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     MyCircle c1 = new MyCircle(); 
     c1.setCircle(20, 0, 0); 

     TilePane root = new TilePane(); 
     root.getChildren().add(c1.getCircle()); 
     //Some kind of mouse event listener, not sure which one should be 
     c1.getCircle().addEventListener(); //pseudo code 

     Scene scene = new Scene(root, 400, 400); 

     primaryStage.setTitle("Circle"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

} 

このサークルを作成して、マウスのクリック、マウスの位置、クリックして、そのようなドラッグやもの、などのすべてのイベントを、処理する必要がありますクラス。

public class MyCircle implements EventHandler{ 
    Circle circle = new Circle(); 

    public void setCircle(int radius, int x, int y){ 
     circle.setRadius(radius); 
     position(x,y); 
     circle.setStrokeWidth(3); 
     circle.setStroke(Color.valueOf("white")); 
    } 

    public Circle getCircle(){ 
     return circle; 
    } 

    public void position(int x, int y){ 
     circle.setTranslateX(x); 
     circle.setTranslateY(y); 
    } 

    public void selected(){ 
     circle.setStroke(Color.valueOf("orange")); 
    } 

    public void unselected() { 
     circle.setStroke(Color.valueOf("white")); 
    } 

    @Override 
    public void handle(Event event) { 
     if (event == MOUSE_CLICKED){ //pseudo code 
      selected(); 
     } 
     else if(event == MOUSE_UNCLICKED){ //pseudo code 
      unselected(); 
     } 
    } 
} 

私はJavaFXの新機能を使用しています。ありがとう!


EDIT:これは私の擬似コードである、と私は、実際の作業コードに変換します。どうすればいいのか分かりません。どんな助けもありがとう。


ANOTHER EDIT:すべては3マークした場所を除いてコードです。私のコメントPsuedo Codeをコード内で探してください。そこで、擬似コードを実際のコードに変更するのに役立つ必要があります。

+0

問題は何ですか?あなたはコードの説明が必要ですか? –

+0

@BoHalim、その擬似コード、私は動作する方法でそれを書いてください。 –

+0

意味、私はこの擬似コードを実際の作業コードに変えたいと思います。どうすればいいのか分かりません。 –

答えて

2

ノードの選択状態を処理するには、ノード内で利用できない知識が必要です。マウスイベントが別の場所(他のノードやルートペインなど)で発生したかどうかを知る必要があるため、疑わしい引数を渡す必要があります。

通常、マウスイベント処理をMyCircleに委任することはお勧めできません。代わりに、そのクラスの選択動作を指定し、選択処理を、問題を処理するのに十分な知識を持つ別のヘルパークラスに委任する方がよいでしょう。私はこの作業をどのように行うことができるかを示すためにgistを作成しました。

public class SelectionDemo extends Application { 
    @Override 
    public void start(Stage primaryStage) { 
     Scene scene = new Scene(createPane(), 400, 400); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private Parent createPane() { 
     BorderPane root = new BorderPane(); 
     SelectionHandler selectionHandler = new SelectionHandler(root); 
     root.addEventHandler(MouseEvent.MOUSE_PRESSED, selectionHandler.getMousePressedEventHandler()); 

     MyCircle c1 = new MyCircle(40, 40, 20); 
     MyCircle c2 = new MyCircle(40, 100, 20); 
     MyCircle c3 = new MyCircle(40, 160, 20); 
     root.getChildren().addAll(c1, c2, c3); 

     return root; 
    } 

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

jfxtras-labsからインタフェースを借りて変更して、選択可能なノードを表しました。これは、選択可能なノードと選択不可能なものを区別するためにこのインタフェースを持って良いことだ:このインタフェースを実装し、notifySelectionメソッドの実装で自分の選択動作を指定する必要があり、選択可能になりたい

/** 
* This interface is based on jfxtras-labs <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/scene/control/window/SelectableNode.java">SelectableNode</a> 
*/ 
public interface SelectableNode { 
    public boolean requestSelection(boolean select); 

    public void notifySelection(boolean select); 
} 

クラス:

public class MyCircle extends Circle implements SelectableNode { 
    public MyCircle(double centerX, double centerY, double radius) { 
     super(centerX, centerY, radius); 
    } 

    @Override 
    public boolean requestSelection(boolean select) { 
     return true; 
    } 

    @Override 
    public void notifySelection(boolean select) { 
     if(select) 
      this.setFill(Color.RED); 
     else 
      this.setFill(Color.BLACK); 
    } 
} 

そして最後に選択ハンドラクラス:

public class SelectionHandler { 
    private Clipboard clipboard; 

    private EventHandler<MouseEvent> mousePressedEventHandler; 

    public SelectionHandler(final Parent root) { 
     this.clipboard = new Clipboard(); 
     this.mousePressedEventHandler = new EventHandler<MouseEvent>() { 
      @Override 
      public void handle(MouseEvent event) { 
       SelectionHandler.this.doOnMousePressed(root, event); 
       event.consume(); 
      } 
     }; 
    } 

    public EventHandler<MouseEvent> getMousePressedEventHandler() { 
     return mousePressedEventHandler; 
    } 

    private void doOnMousePressed(Parent root, MouseEvent event) { 
     Node target = (Node) event.getTarget(); 
     if(target.equals(root)) 
      clipboard.unselectAll(); 
     if(root.getChildrenUnmodifiable().contains(target) && target instanceof SelectableNode) { 
      SelectableNode selectableTarget = (SelectableNode) target; 
      if(!clipboard.getSelectedItems().contains(selectableTarget)) 
       clipboard.unselectAll(); 
      clipboard.select(selectableTarget, true); 
     } 
    } 

    /** 
    * This class is based on jfxtras-labs 
    * <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/scene/control/window/Clipboard.java">Clipboard</a> 
    * and 
    * <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/util/WindowUtil.java">WindowUtil</a> 
    */ 
    private class Clipboard { 
     private ObservableList<SelectableNode> selectedItems = FXCollections.observableArrayList(); 

     public ObservableList<SelectableNode> getSelectedItems() { 
      return selectedItems; 
     } 

     public boolean select(SelectableNode n, boolean selected) { 
      if(n.requestSelection(selected)) { 
       if (selected) { 
        selectedItems.add(n); 
       } else { 
        selectedItems.remove(n); 
       } 
       n.notifySelection(selected); 
       return true; 
      } else { 
       return false; 
      } 
     } 

     public void unselectAll() { 
      List<SelectableNode> unselectList = new ArrayList<>(); 
      unselectList.addAll(selectedItems); 

      for (SelectableNode sN : unselectList) { 
       select(sN, false); 
      } 
     } 
    } 
} 

enter image description here

1

これは私がそれをした方法です...シンプルで簡単

メインクラス

public class Lab05 extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     double width = 400; 
     double height = 400; 

     int num_of_circles = 5; 
     int radius_of_circles = 20; 

     BorderPane root = new BorderPane(); 

     for (int i = 0; i < num_of_circles; i++) { 
      MyCircle temp = createCircle(radius_of_circles, (50 * i) + 1, 100); 
      temp.setFrame(width, height); 
      root.getChildren().add(temp.getCircle()); 
      temp.getCircle().addEventFilter(MouseEvent.ANY, temp); 
     } 

     Scene scene = new Scene(root, width, height); 

     primaryStage.setTitle("Lab 05"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

    public static MyCircle createCircle(int radius, int x, int y){ 
     MyCircle circle = new MyCircle(); 
     circle.setCircle(radius, x, y); 
     return circle; 
    } 
} 

MyCircleクラス

public class MyCircle implements EventHandler<MouseEvent>{ 
    private static double frameX = 0; 
    private static double frameY = 0; 
    private final Circle circle = new Circle(); 
    private static final List<Circle> CIRCLES = new ArrayList<>(); 

    public void setCircle(int radius, int x, int y){ 
     circle.setRadius(radius); 
     position(x,y); 
     circle.setStrokeWidth(3); 
     circle.setStroke(Color.valueOf("white")); 
     CIRCLES.add(circle); 
    } 

    public void setFrame(double x, double y){ 
     frameX = x; 
     frameY = y; 
    } 

    public Circle getCircle(){ 
     return circle; 
    } 

    public void position(double x, double y){ 
     if (x < frameX && x > 0) 
      circle.setCenterX(x); 
     if (y < frameY && y > 0) 
      circle.setCenterY(y); 
    } 

    public void selected(){ 
     CIRCLES.stream().forEach((c) -> { 
      c.setStroke(Color.valueOf("white")); 
     }); 
     circle.setStroke(Color.valueOf("orange")); 
    } 

    public void unselected() { 
     circle.setStroke(Color.valueOf("white")); 
    } 

    @Override 
    public void handle(MouseEvent event) { 
     if (event.getEventType() == MouseEvent.MOUSE_PRESSED){ 
      selected(); 
     } 
     else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED){ 
      position(event.getX(), event.getY()); 
     } 
    } 
} 
3

あなたのタスクを達成を助けるために、内蔵のJava機能の一部を使用することができます。

たとえば、CSS PsuedoClassesおよびTogglesは、ToggleGroupで管理されています。

このようにする必要はありません。これらの他のJavaFX機能を使用していないソリューションはうまくいきます。標準のJavaFX関数のいくつかを使うのはまあまあです。

lights

LightApp.java

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 

public class LightApp extends Application { 

    @Override 
    public void start(final Stage stage) throws Exception { 
     final Bulb[] bulbs = { 
       new Bulb(), 
       new Bulb(), 
       new Bulb() 
     }; 

     Scene scene = new Scene(new LightArray(bulbs)); 
     stage.setScene(scene); 
     stage.show(); 
    } 

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

} 

LightArray.java

import javafx.geometry.Insets; 
import javafx.scene.control.ToggleGroup; 
import javafx.scene.layout.HBox; 

public class LightArray extends HBox { 
    public LightArray(Bulb... bulbs) { 
     super(10, bulbs); 
     setPadding(new Insets(10)); 

     ToggleGroup toggleGroup = new ToggleGroup(); 
     for (Bulb bulb: bulbs) { 
      bulb.setToggleGroup(toggleGroup); 
     } 

     setOnMouseClicked(event -> { 
      if (event.getTarget() instanceof Bulb) { 
       toggleGroup.selectToggle((Bulb) event.getTarget()); 
      } else { 
       toggleGroup.selectToggle(null); 
      } 
     }); 

     getStylesheets().add(
       this.getClass().getResource("bulb.css").toExternalForm() 
     ); 
    } 
} 

Bulb.java

import javafx.beans.property.*; 
import javafx.css.PseudoClass; 
import javafx.scene.control.*; 
import javafx.scene.shape.Circle; 

class Bulb extends Circle implements Toggle { 
    private ObjectProperty<ToggleGroup> toggleGroup = new SimpleObjectProperty<>(); 

    Bulb() { 
     super(30); 
     getStyleClass().add("bulb"); 
    } 

    @Override 
    public void setSelected(boolean selected) { 
     this.selected.set(selected); 
    } 

    @Override 
    public boolean isSelected() { 
     return selected.get(); 
    } 

    @Override 
    public BooleanProperty selectedProperty() { 
     return selected; 
    } 

    public BooleanProperty selected = 
      new BooleanPropertyBase(false) { 
       @Override protected void invalidated() { 
        pseudoClassStateChanged(ON_PSEUDO_CLASS, get()); 
       } 

       @Override public Object getBean() { 
        return Bulb.this; 
       } 

       @Override public String getName() { 
        return "on"; 
       } 
      }; 

    private static final PseudoClass 
      ON_PSEUDO_CLASS = PseudoClass.getPseudoClass("on"); 

    @Override 
    public ToggleGroup getToggleGroup() { 
     return toggleGroup.get(); 
    } 

    @Override 
    public void setToggleGroup(ToggleGroup toggleGroup) { 
     this.toggleGroup.set(toggleGroup); 
    } 

    @Override 
    public ObjectProperty<ToggleGroup> toggleGroupProperty() { 
     return toggleGroup; 
    } 
} 

bulb.css

.bulb { 
    -fx-fill: lightslategray; 
} 

.bulb:on { 
    -fx-fill: gold; 
} 

しばしばJavaFXの(と私はここに行っていない)で行われ、追加の共通点は、(例えば、CSSでスタイリングできるアイテムを作ることですリージョンまたはペイン)を選択し、スタイリングを適用します。例えば、Bulb extend Circleの代わりにStackPaneを拡張すると、複数のレイヤーとsvgシェイプ(これはラジオボタンのような他の同様のものが実装されている方法です)を使って電球の形をCSSでカスタマイズすることができます。