4

JavaFX 2.2 で非表示ノードの MouseEvents を受信しようとしています。たとえば、マウスがホバーしたときにアクションをトリガーする必要がある、インタラクティブだが目に見えないゾーンと考えてください。問題は、これが静的に定義されたゾーンではなく、アプリケーションによって移動およびサイズ変更できる複数のゾーン (多数) があることです。したがって、私のユースケースでは、マウスの動きをグローバルにリッスンし、MouseMove-Events の手動検出を実行すると、多くのオーバーヘッドが発生します。

現在、私は透明な Rectangle ( new Rectangle(200, 100, Color.TRANSPARENT)) を試していますが、実際の / 最終的なアプリケーションは、実際には他のコンポーネントのドラッグ可能なコンテナーであるため、ある種のペインを使用します (コンポーネントでいっぱいでない場合、透明な領域があり、これらの透明な領域でも MouseMoves を検出する必要があります)。

さらに、ノードの可視性に応じてJavaFX 2.2が一般的にMouseEventsを処理する方法をよりよく理解するのに役立つ回答をいただければ幸いです。

私の実験は、これまでのところ次の一般的な洞察を示しています。

  • 透明なシーンの場合: マウス イベントは、ユーザーが透明な領域をクリックしたときに、外部アプリケーション (視覚的にはシーンの下) にのみ渡されます。ユーザーがシーンの可視ピクセルをクリックしたときに、マウスイベントを「OS に」渡す方法はありません。右?

  • 他のノードの上のペインは、MouseTransparent であるか、MouseClick が非表示 (透明) 領域に表示されない限り、デフォルトですべての MouseEvent を飲み込みます。

  • pickOnBounds(true|false)trueMouseEvents の境界ベース (四角形) 検出を有効にする( ) か、または無効にする ( false) ためにあります。後者は、可視ピクセル/領域に対してのみマウスイベントを効果的に処理します。pickOnBounds(true)完全に見えないノードでは機能しないようです。右?

  • 私の実験では、ノードが表示されると見なされるには、少なくとも - の塗りつぶしが必要であることが示されましたnew Color(1,1,1,0.004)。低いアルファ値は不可視と見なされるため、MouseEvents が呼び出されたとしても処理されませんpickOnBounds(true)

私はこれを正しく理解しましたか?その場合、不可視の Node が MouseEvents を受け取る方法はありません。

それとも働くために特別な要件がありpickOnBoundsますか?ノードが表示された後などにのみ呼び出す必要がありますか? 他の提案はありますか?

4

1 に答える 1

2

一言で言えば: Node.setOpacity(0.0) を使用してください

opacity プロパティは、ノードがイベントを受け取る能力に影響を与えることなく、ノードの「視覚的な透明度」を制御します。 APIdocsを参照してください。このプロパティを 0 に設定すると、あなた (および私) が探していた効果が得られます: 非表示ですが、マウスに敏感な「ホット ゾーン」-ノード。

これは、Node.setVisible(false)私が最初に試したものとは対照的です。そのアプローチは、イベント処理も無効にします。Node.setVisible() APIdocs から:

非表示のノードは、マウス イベントやキーボード フォーカスを受け取ることはなく、非表示になったときにキーボード フォーカスを維持することもありません。

「見えない」とは、実際には「呼び出した後」を意味setVisible(false)し、画像内の不透明または完全に透明なピクセルと混同しないでください。

評判が悪いため、スクリーンショットを直接投稿することはできません。そのため、 以下のコード例のホット ゾーン レイアウトを示すスクリーンショットへのリンク(明らかな理由により、スクリーンショットではノードの不透明度が 0 に設定されていません)。

この例では、長方形と円を含むグループをホット ゾーンとして使用して、マウス イベントがキャプチャされる領域を定義しています。不透明度プロパティとマウス ハンドラーは、子ではなく、グループでのみ設定する必要があります。

そうすれば、任意の形状のホット ゾーンを構築できます。透明な領域を持つ画像をホット ゾーンとして使用する場合は、バウンディング ボックスだけでなく、実際の画像コンテンツが考慮されるように、そのpickOnBoundsプロパティを に設定する必要があります。false

それが役に立てば幸い!

public class HotZoneTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        StackPane root = new StackPane();
        Scene scene = new Scene(root, 300, 250);
        primaryStage.setScene(scene);
        primaryStage.show();

        Group hotZone = new Group();
        root.getChildren().add(hotZone);

        hotZone.getChildren().add(new Rectangle(10, 20, 100, 50));
        hotZone.getChildren().add(new Circle(50, 120, 20));

        hotZone.setOpacity(0.4); //set to 0.0 to make invisible

        EventHandler handler = new EventHandler() {
            @Override
            public void handle(Event e) {
                System.out.println("hotZone mouse event: " + e);
            }
        };
        hotZone.addEventHandler(MouseEvent.MOUSE_ENTERED, handler);
        hotZone.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
        hotZone.addEventHandler(MouseEvent.MOUSE_EXITED, handler);

    }

編集:あなたの特定のサブ質問に関して(私が知る限り、私はFXの達人ではありません:))

ユーザーがシーンの可視ピクセルをクリックしたときに、マウスイベントを「OS に」渡す方法はありません。右?

興味深い、それを試したことはありません。何がうまくいくかについての純粋な推測:マウスイベントの画面座標を取得し、ウィンドウを邪魔にならないように移動し、java.awt.Robot を使用して OS カーソルをマウスイベントの座標に移動し、必要に応じてそこでクリックを発生させ、ウィンドウバック。注意: 完全なハックのように聞こえます!

他のノードの上のペインは、MouseTransparent であるか、MouseClick が非表示 (透明) 領域に表示されない限り、デフォルトですべての MouseEvent を飲み込みます。

私もそう理解しています。ただし、マウスの出入りについてはわかりません。MOUSE_ENTERED_TARGET/MOUSE_EXITED_TARGET少なくとも親でリッスンして、どの子が出入りしたかを判断できます。子がイベントを受信しないようにする場合は、親にイベント フィルターを登録し、そこでイベントを消費します。

pickOnBounds(true|false) は、MouseEvents の境界ベース (四角形) 検出を有効 (true) または無効 (false) にするためにあります。後者は、可視ピクセル/領域に対してのみマウスイベントを効果的に処理します。

はい。

pickOnBounds(true) は、完全に非表示のノードでは機能しないようです。

を呼び出して非表示にしたノードの場合は true ですsetInvisible(true)

私の実験では、ノードが表示されると見なされるには、少なくとも - new Color(1,1,1,0.004) の塗りつぶしが必要であることが示されました。

コメントはできませんが、あなたの実験結果は正しいようです。

その場合、不可視の Node が MouseEvents を受け取る方法はありません。

を使用.setOpacity(0.0)すると、ノードは「視覚的に見えなくなります」が、イベントを受け取り、setbickOnBounds を尊重します

于 2015-02-05T09:47:22.537 に答える