Вопрос по javafx-2, event-handling, transparency, mouseevent – JavaFX: Как сделать Node частично прозрачным для мыши?

6
Упрощенная проблема:

Сделайте один Узел «A» поверх другого Узла «B» полупрозрачным для MouseEvents, чтобы События достигли нижележащего Узла «B». Оба узла имеют одинаковый размер, но узел «А» имеет полупрозрачное фоновое изображение, поэтому видна половина узла «В».

Реальная проблема:

У меня есть меню вкладок. Каждую вкладку можно перетащить, чтобы развернуть соответствующий слой меню. Поэтому каждый слой вкладки представляет собой панель с частично прозрачным фоном (в основном, многоугольником), прозрачная часть которого также должна быть прозрачной для MouseEvents.

Иллюстрация (которую я пока не могу опубликовать, см. Ссылку:Иллюстрация вкладок(темно-зеленая линия - граница зеленой панели) показывает основной принцип: представьте, что видны только вкладки, а сам слой можно потянуть вправо, чтобы просмотреть его содержимое.

Итак, вопрос в том, как сделать область узла прозрачной для MouseEvents, не делая весь узел прозрачным?

Спасибо за помощь!

Обновить:

Для выяснения простой проблемы приведем соответствующий код:

//Create parent group
Group root = new Group();

//Create linear gradient, so one side is transparent
Stop[] stops = new Stop[] { new Stop(0, Color.rgb(0, 255, 0, 0.0)), new Stop(1, Color.rgb(0, 255, 0, 1.0))};
LinearGradient lg1 = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops);

//Create the rectangles
Rectangle A = new Rectangle(100, 50, lg1);
Rectangle B = new Rectangle(100,50, Color.RED);

//Add eventHandlers
A.setOnMouseClicked(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent e) {
        System.out.println("Clicked A");
    }
});
B.setOnMouseClicked(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent e) {
        System.out.println("Clicked B");
    }
});
root.getChildren().addAll(B, A);

//Add to Scene..

Надеюсь это поможет.

Я не особо задумывался, но могу предложить кое-что: создать прямоугольник, установить его цвет прозрачным (кажется, Color.TRANSPARENT). Сделайте его не прозрачным для мыши, и свяжите его высоту с частью высоты целевого узла «A». Поместите его поверх целевого узла «A» и запишите код события, передаваемого в базовый узел «A». Сделайте узел "А" прозрачным. Это работает? Alexander Kirov

Ваш Ответ

1   ответ
6

pickOnBounds собственность, этомай помочь в вашей ситуации, но мне не понятно, не увидев вашу попытку кода, которая не помогает из-за упрощенной проблемы.

node.setPickOnBounds (правда)

Если pickOnBounds имеет значение true, тогда выбор рассчитывается путем пересечения с границами этого узла, иначе выбор рассчитывается путем пересечения с геометрической формой этого узла.

Приведенный ниже код демонстрирует, как это можно использовать, создав квадрат, наложенныйImageView дляImage который содержит прозрачные пиксели. ЕслиpickOnBounds для ImageView установлено значение true, тогда, даже если вы нажмете на прозрачные пиксели на изображении, ImageView получит событие mouseClick. ЕслиpickOnBounds устанавливается в false для ImageView, тогда, даже если вы нажмете на прозрачные пиксели в изображении, ImageView не будет обрабатывать щелчок, и событие click будет получено узлом за изображением.

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class PickOnBoundsDemo extends Application {
  public static void main(String[] args) { Application.launch(args); }
  @Override public void start(Stage stage) {
    final Rectangle back  = new Rectangle(128, 128);
    back.setFill(Color.FORESTGREEN);
    final ImageView front = new ImageView("http://icons.iconarchive.com/icons/aha-soft/free-large-boss/128/Wizard-icon.png");
    // icon: Linkware (Backlink to http://www.aha-soft.com required)

    final StackPane pickArea = new StackPane();
    pickArea.getChildren().addAll(
      back, 
      front
    );

    final ToggleButton pickTypeSelection = new ToggleButton("Pick On Bounds");
    final Label pickResult = new Label();

    Bindings.bindBidirectional(front.pickOnBoundsProperty(), pickTypeSelection.selectedProperty());

    front.setOnMouseClicked(new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent t) {
        pickResult.setText("Front clicked");
      }
    });

    back.setOnMouseClicked(new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent t) {
        pickResult.setText("Back clicked");
      }
    });

    VBox layout = new VBox(10);
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
    layout.getChildren().setAll(
      pickArea,
      new Label("Click inside the above area to test mouse picking."),
      pickTypeSelection,
      pickResult
    );
    layout.setAlignment(Pos.CENTER);

    stage.setScene(new Scene(layout));
    stage.show();
  }
}
Спасибо за ваш комментарий. Я попробую это и добавлю фоновое изображение в качестве ImageView вместо установки свойства background-image CSS. MoeSzyslak
Ваше решение работает! Большое спасибо. Мне пришлось установить pickOnBounds (false) для всех узлов, содержащих объект ImageView, чтобы событие не было перехвачено родительским узлом. MoeSzyslak

Похожие вопросы