JavaFX通过透明节点将MouseEvents传递给子节点 [英] JavaFX Pass MouseEvents through Transparent Node to Children

查看:144
本文介绍了JavaFX通过透明节点将MouseEvents传递给子节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在java doc中,它代表:

  import javafx.application.Application; 
import javafx.collections。*;
import javafx.event.EventHandler;
import javafx.scene。*;
import javafx.scene.chart。*;
import javafx.scene.effect.Glow;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Path;
import javafx.stage.Stage;

公共类LineChartSample扩展Application {
@SuppressWarnings(unchecked)
@Override public void start(阶段阶段){
//初始化数据
ObservableList< XYChart.Data> data = FXCollections.observableArrayList(
new XYChart.Data(1,23),new XYChart.Data(2,14),new XYChart.Data(3,15),new XYChart.Data(4,24),新的XYChart.Data(5,34),新的XYChart.Data(6,36),新的XYChart.Data(7,22),新的XYChart.Data(8,45),新的XYChart.Data(9,43),新的XYChart.Data(10,17),新的XYChart.Data(11,29),新的XYChart.Data(12,25)
);
ObservableList< XYChart.Data> reversedData = FXCollections.observableArrayList(
new XYChart.Data(1,25),new XYChart.Data(2,29),new XYChart.Data(3,17),new XYChart.Data(4,43),新的XYChart.Data(5,45),新的XYChart.Data(6,22),新的XYChart.Data(7,36),新的XYChart.Data(8,34),新的XYChart.Data(9,24),新的XYChart.Data(10,15),新的XYChart.Data(11,14),新的XYChart.Data(12,23)
);

//创建图表
final LineChart< Number,Number> lineChart = createChart(data);
final LineChart< Number,Number> reverseLineChart = createChart(reversedData);
StackPane layout = new StackPane();
layout.getChildren()。setAll(
lineChart,
reverseLineChart
);

//显示场景。
场景场景=新场景(布局,800,600);
stage.setScene(场景);
stage.show();

//将一个折线图设为绿色,这样很容易看出哪个是哪个。
reverseLineChart.lookup(。default-color0.chart-series-line)。setStyle( - fx-stroke:forestgreen;);

//关闭图表边界的选择,以便点击形状时仅点击注册。
turnOffPickOnBoundsFor(lineChart);
turnOffPickOnBoundsFor(reverseLineChart);

//将鼠标悬停在折线图中的线条上时添加光晕,以便您可以看到它们已被选中。
addGlowOnMouseOverData(lineChart);
addGlowOnMouseOverData(reverseLineChart);
}

@SuppressWarnings(unchecked)
private void turnOffPickOnBoundsFor(Node n){
n.setPickOnBounds(false);
if(n instanceof Parent){
for(Node c:((Parent)n).getChildrenUnmodifiable()){
turnOffPickOnBoundsFor(c);
}
}
}

private void addGlowOnMouseOverData(LineChart< Number,Number> lineChart){
//使图表中的第一个系列发光当你把鼠标放在它上面。
节点n = lineChart.lookup(。chart-series-line.series0);
if(n!= null&& n instanceof Path){
final path path =(Path)n;
final Glow glow = new Glow(.8);
path.setEffect(null);
path.setOnMouseEntered(new EventHandler< MouseEvent>(){
@Override public void handle(MouseEvent e){
path.setEffect(glow);
}
});
path.setOnMouseExited(new EventHandler< MouseEvent>(){
@Override public void handle(MouseEvent e){
path.setEffect(null);
}
});
}
}

私有LineChart<数字,数字> createChart(ObservableList< XYChart.Data> data){
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel(月数);
final LineChart< Number,Number> lineChart = new LineChart<>(xAxis,yAxis);
lineChart.setTitle(Stock Monitoring,2010);
XYChart.Series series = new XYChart.Series(data);
series.setName(我的投资组合);
series.getData()。addAll();
lineChart.getData()。add(series);
lineChart.setCreateSymbols(false);
lineChart.setLegendVisible(false);
返回lineChart;
}

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


In the java doc it says for setMouseTransparent that is affects all children as well as the parent.

How can it be made so only the parent's transparent areas (can see other nodes below it but not responding to mouse events) are transparent to mouse events so that the nodes below it may receive them.

This happens when stacking two XYCharts in the same pane. Only the last one added can receive events.

解决方案

Set pickOnBounds for the relevant nodes to false, then clicking on transparent areas in a node won't register a click with that node.

Defines how the picking computation is done for this node when triggered by a MouseEvent or a contains function call. If pickOnBounds is true, then picking is computed by intersecting with the bounds of this node, else picking is computed by intersecting with the geometric shape of this node.

Sample Output

This sample is actually far more complicated than is necessary to demonstrate the pickOnBounds function - but I just did something this complicated so that it shows what happens "when stacking two XYCharts in the same pane" as mentioned in the poster's question.

In the sample below two line charts are stacked on top of each other and the mouse is moved over the data line in one chart which has a glow function attached to it's mouseenter event. The mouse is then moved off of the first line chart data and the glow is removed from it. The mouse is then placed over the second line chart data of an underlying stacked chart and the glow is added to that linechart in the underlying stacked chart.

This sample was developed using Java8 and the coloring and behaviour described is what I exeperienced running the program on Mac OS X and Java 8b91.

Sample Code

The code below is just for demonstrating that pickOnBounds does work for allowing you to pass mouse events through transparent regions stacked on top of opaque node shapes. It is not a recommended code practice to follow for styling lines in charts (you are better off using style sheets than lookups for that), it is also not necessary that you use a line chart stack to get multiple series on a single chart - it was only necessary or simpler to do these things to demonstrate the pick on bounds concept application for this answer.

Note the recursive call to set the pickOnBounds property for the charts after the charts have been shown on a stage and all of their requisite nodes created.

Sample code is an adaption of JavaFX 2 XYChart.Series and setOnMouseEntered:

import javafx.application.Application;
import javafx.collections.*;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.chart.*;
import javafx.scene.effect.Glow;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Path;
import javafx.stage.Stage;

public class LineChartSample extends Application {
  @SuppressWarnings("unchecked")
  @Override public void start(Stage stage) {
    // initialize data
    ObservableList<XYChart.Data> data = FXCollections.observableArrayList(
      new XYChart.Data(1, 23),new XYChart.Data(2, 14),new XYChart.Data(3, 15),new XYChart.Data(4, 24),new XYChart.Data(5, 34),new XYChart.Data(6, 36),new XYChart.Data(7, 22),new XYChart.Data(8, 45),new XYChart.Data(9, 43),new XYChart.Data(10, 17),new XYChart.Data(11, 29),new XYChart.Data(12, 25)
    );
    ObservableList<XYChart.Data> reversedData = FXCollections.observableArrayList(
        new XYChart.Data(1, 25), new XYChart.Data(2, 29), new XYChart.Data(3, 17), new XYChart.Data(4, 43), new XYChart.Data(5, 45), new XYChart.Data(6, 22), new XYChart.Data(7, 36), new XYChart.Data(8, 34), new XYChart.Data(9, 24), new XYChart.Data(10, 15), new XYChart.Data(11, 14), new XYChart.Data(12, 23)
    );

    // create charts
    final LineChart<Number, Number> lineChart        = createChart(data);
    final LineChart<Number, Number> reverseLineChart = createChart(reversedData);
    StackPane layout = new StackPane();
    layout.getChildren().setAll(
      lineChart,
      reverseLineChart
    );

    // show the scene.
    Scene scene = new Scene(layout, 800, 600);
    stage.setScene(scene);
    stage.show();

    // make one line chart line green so it is easy to see which is which.
    reverseLineChart.lookup(".default-color0.chart-series-line").setStyle("-fx-stroke: forestgreen;");

    // turn off pick on bounds for the charts so that clicks only register when you click on shapes.
    turnOffPickOnBoundsFor(lineChart);
    turnOffPickOnBoundsFor(reverseLineChart);

    // add a glow when you mouse over the lines in the line chart so that you can see that they are chosen.
    addGlowOnMouseOverData(lineChart);
    addGlowOnMouseOverData(reverseLineChart);
  }

  @SuppressWarnings("unchecked")
  private void turnOffPickOnBoundsFor(Node n) {
    n.setPickOnBounds(false);
    if (n instanceof Parent) {
      for (Node c: ((Parent) n).getChildrenUnmodifiable()) {
        turnOffPickOnBoundsFor(c);
      }
    }
  }

  private void addGlowOnMouseOverData(LineChart<Number, Number> lineChart) {
    // make the first series in the chart glow when you mouse over it.
    Node n = lineChart.lookup(".chart-series-line.series0");
    if (n != null && n instanceof Path) {
      final Path path = (Path) n;
      final Glow glow = new Glow(.8);
      path.setEffect(null);
      path.setOnMouseEntered(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent e) {
          path.setEffect(glow);
        }
      });
      path.setOnMouseExited(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent e) {
          path.setEffect(null);
        }
      });
    }
  }

  private LineChart<Number, Number> createChart(ObservableList<XYChart.Data> data) {
    final NumberAxis xAxis = new NumberAxis();
    final NumberAxis yAxis = new NumberAxis();
    xAxis.setLabel("Number of Month");
    final LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
    lineChart.setTitle("Stock Monitoring, 2010");
    XYChart.Series series = new XYChart.Series(data);
    series.setName("My portfolio");
    series.getData().addAll();
    lineChart.getData().add(series);
    lineChart.setCreateSymbols(false);
    lineChart.setLegendVisible(false);
    return lineChart;
  }

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

这篇关于JavaFX通过透明节点将MouseEvents传递给子节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆