提问者:小点点

JavaFX面积图:在XYChart区域上设置鼠标透明度,但不设置其子数据节点的透明度


一直在挠头,研究了一段时间,但没有运气。

我有一个javaFX项目,我在其中创建了一个带有4组系列的areachart,其中最后一组只有可见的点(黑色Xs):

我还实现了通过突出显示一个区域来深入图表的能力。这都是通过各种鼠标处理程序实现的,但本质上它是一个半透明的黄色矩形(高亮显示),可以随着鼠标的拖动而调整大小:

    private void setMouseHandler() {
final Axis<Date> xAxis = gcChart.getXAxis();
final Axis<Number> yAxis = gcChart.getYAxis();        
final Node chartBackground = gcChart.lookup(".chart-plot-background");
for (Node n: chartBackground.getParent().getChildrenUnmodifiable()) {
    if (n != chartBackground && n != xAxis && n != yAxis && n != highlight) {
    n.setMouseTransparent(true);
    }
}   
chartBackground.setOnMouseEntered(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
        exitedChart = false;
    }
    }

});


//grab the initial values so if dragged we have them
chartBackground.setOnMousePressed(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {     

    if (mouseEvent.isPrimaryButtonDown()){
            Bounds chartAreaBounds = yAxis.localToParent(yAxis.getBoundsInParent()); //chartBackground.localToScene(chartBackground.getBoundsInLocal());                                  
            xShift = chartAreaBounds.getMaxX() -10;  //account for Y Axis area on the chart and side tabs
            origX = mouseEvent.getX() + xShift;
            highlight.setVisible(true);
            highlight.setX(origX);
            highlight.setY(chartAreaBounds.getMinY()+xAxis.getHeight());
            highlight.setHeight(chartAreaBounds.getMaxY()-xAxis.getHeight());

            // Don't want to re-render the chart if we are already zoomed out.      
            firstSelDate = xAxis.getValueForDisplay(mouseEvent.getX());
    }
    else{
     // Are we zoomed in?
        if (seriesCache.size() >= 2){
            logger.info("Zooming out of chart");
            Platform.runLater(new Runnable() {

            @Override
            public void run() {
                removeChartFromScene();
                // return to last series in cache
                new Thread(new GenerateDataTask(null, null, true)).start();
            }

            });
            firstSelDate = null;
        }
    }

    }

});

//must enable FullDrag to detect a drag entering into nodes other than the chart ie. highlight
chartBackground.setOnDragDetected(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
        chartBackground.startFullDrag();
    }
    }

});

chartBackground.setOnMouseDragged(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
            //only set drag values if in the bounds of yAxis
            if (!exitedChart){
                double position = mouseEvent.getX() + xShift;
                highlight.setX(origX <= position? origX : position);                    
                highlight.setWidth(origX <= position? position-origX: origX-position);

                // this may be whats causing the slow drag..
                lastSelDate = xAxis.getValueForDisplay(mouseEvent.getX());   
            }
    }
    }

});     
chartBackground.setOnMouseReleased(new EventHandler<MouseEvent>() {

    public void handle(MouseEvent mouseEvent) {     
        //Check if drag was backwards and if so swap dates
        if (lastSelDate!=null && firstSelDate.compareTo(lastSelDate)>0){
            Date tempDate = firstSelDate;
            firstSelDate=lastSelDate;
            lastSelDate=tempDate;
        }
        //mouse has been released so cleanup the highlight
        highlight.setX(0);
        highlight.setWidth(0);
        highlight.setVisible(false);
        //Set both sets of series in the chart to the subset selected
        if (lastSelDate != null && firstSelDate.compareTo(lastSelDate) != 0) {
            logger.info("Zooming into chart");
            removeChartFromScene();
            // show the subset of data
            new Thread(new GenerateDataTask(firstSelDate, lastSelDate, false)).start();

        }
        lastSelDate = null;

    }

});
yAxis.setOnMouseDragEntered(new EventHandler<MouseDragEvent>() {

    @Override 
    public void handle(MouseDragEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
            exitedChart = true;

            //Account for lag in listener when hitting the yAxis - pull highlight rigt to the edge
            highlight.setX(yAxis.getBoundsInParent().getMaxX());
            highlight.setWidth(origX-yAxis.getBoundsInParent().getMaxX());
    }
    }

});

//detect drag if pulled back into highlight area
highlight.setOnMouseDragEntered(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
        exitedChart = false;
    }
    }

});
}

为了使此突出显示功能正常工作而不会遇到很多麻烦,我将图表中的大多数节点设置为对鼠标透明:

    for (Node n: chartBackground.getParent().getChildrenUnmodifiable()) {
    if (n != chartBackground && n != xAxis && n != yAxis && n != highlight) {
    n.setMouseTransparent(true);
    }
}

我的问题是,我现在正在尝试在顶部图表系列(黑色x点)上设置工具提示,但是我能够让它们工作的唯一方法是将这些节点以及它们的父节点(组)和祖父节点(XYChart)设置为不透明。在这样做时,我破坏了高亮功能。

我已经尝试过setPickOnBands,但据我所知,它只控制鼠标是否“看到”给定节点的不可见部分。如果我的理解是正确的,那么在这种情况下就行不通了,因为拖动例程需要忽略系列的可见区域(下降到图表背景),但不能忽略黑色Xs(XYChart.Data节点)。

有什么方法(除了重写鼠标处理)可以让鼠标看得见那组序列而不看得见其他的吗?


共1个答案

匿名用户

mouseTranparent属性使“节点(及其所有子节点)对鼠标事件完全透明。”,因此您不能使用此属性来获得您想要的行为。

相反,请尝试在图表上设置一个事件过滤器,该过滤器将根据事件目标有选择地忽略事件。鼠标事件的事件过滤器可以查询事件的源和目标,并选择消费事件(忽略它),或者不消费事件(允许节点的默认鼠标处理程序生效)。

如果您需要帮助查看正在发生的事件,以便决定使用或通过什么,那么您可以使用ScenicView的事件记录功能。