JavaFX PiChart,我的悬停值闪烁

时间:2015-06-05 08:48:50

标签: javafx popup label

上下文:

你好! 我正在尝试创建一个小弹出窗口,在鼠标悬停时显示切片的值,在我的 PieChart (使用JavaFX)上。

我在 LineChart AreaChart 等方面取得了成功。感谢这篇文章:JavaFX LineChart Hover Values(非常感谢Jewelsea的帮助)。

问题(1/2):

但是使用 PieChart ,我遇到了一个问题:弹出窗口正在闪烁oO

enter image description here

我的代码:

使用句法颜色:https://bpaste.net/show/12838ad6b2e2

import java.util.ArrayList;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import com.alpha.client.view.nodes.stats.statsEngine.beans.ListRepere;
import com.alpha.client.view.nodes.stats.statsEngine.beans.OptionsChart;
import com.alpha.client.view.nodes.stats.statsEngine.beans.ValueStat;

/**
 *
 * @author Zombkey
 */
public class PieChartNode implements ChartNode {

//My personnal attributes
private ListRepere categories;
private ArrayList<ValueStat> values;
//The PieChart
private PieChart chart;

//The data of Chart, will be fill by a thread
private ObservableList<PieChart.Data> pieChartData;
//The node which contain chart and label
private Group group;
//The Label 
private final Label caption;

public PieChartNode(ListRepere categories, ArrayList<ValueStat> values, OptionsChart optionsChart) {
    this.categories = categories;
    this.values = values;

    //New Group
    group = new Group();
    //I must use a StackPane to place Label hover Chart
    StackPane pane = new StackPane();
    group.getChildren().add(pane);

    //Init' PieChart
    pieChartData = FXCollections.observableArrayList();
    chart = new PieChart(pieChartData);
    chart.setStartAngle(180.0);
    //Add chart to StackPane
    pane.getChildren().add(chart);

    //Init Popup(Label)
    caption = new Label("");
    caption.setVisible(false);
    caption.getStyleClass().addAll("chart-line-symbol", "chart-series-line");
    caption.setStyle("-fx-font-size: 12; -fx-font-weight: bold;");
    caption.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
    //Add Label to StackPane
    pane.getChildren().add(caption);
}

@Override
public Node getNodeGraph() {
    return (Node) group;
}

@Override
public Task initTaskFormat() {
    Task<Void> task = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            //i and sizeOfallElements are just use for ProgressBar 
            int i = 0;
            int sizeOfallElements = values.size();
            updateProgress(i, sizeOfallElements);

            //For Each ValueStat (a Personnal pojo Class), I must create a slice 
            for (ValueStat v : values) {
                //Create the PieChart.Data and add it to ObservableList
                PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(), v.getDoubleValue());
                pieChartData.add(dataTemp);

                //HERE, the interessante code !
                //At the same way that the LineChart, I add Event when mouse entered and mouse exited.
                //When mouse entered (on the slice of PieChart)
                dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED,
                        new EventHandler<MouseEvent>() {
                            @Override
                            public void handle(MouseEvent e) {
                                System.out.println("MOUSE_ENTERED : "+dataTemp.getName());
                                //I display Label
                                caption.setVisible(true);
                                //I move Label near the mouse cursor
                                caption.setTranslateX(e.getX());
                                caption.setTranslateY(e.getY());
                                //I hide the mouse cursor
                                dataTemp.getNode().setCursor(Cursor.NONE);
                                //I change text of Label
                                caption.setText(String.valueOf(dataTemp.getPieValue()) + "\n" + dataTemp.getName());
                                //I try to change the frame color of Label
                                caption.getStyleClass().add(dataTemp.getNode().getStyleClass().get(2));
                            }
                        });

                //When mouse exited (the slice of PieChart)
                dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_EXITED,
                        new EventHandler<MouseEvent>() {
                            @Override
                            public void handle(MouseEvent e) {
                                System.out.println("MOUSE_EXITED : "+dataTemp.getName());
                                //I Hide Label
                                caption.setVisible(false);
                                //I show the mouse cursor
                                dataTemp.getNode().setCursor(Cursor.DEFAULT);
                            }
                        });
                //Update progress
                updateProgress(i++, sizeOfallElements);
            }
            return null;
        }
    };
    return task;
}
}

问题(2/2):

问题是事件(MOUSE_ENTERED和MOUSE_EXITED)经常发出而不是一次。

Ex: 我只是放入,然后推迟,我的鼠标悬停一片。 这是控制台上的结果:

MOUSE_ENTERED : BC
MOUSE_EXITED : BC
MOUSE_ENTERED : BC
MOUSE_EXITED : BC
MOUSE_ENTERED : BC
MOUSE_EXITED : BC
MOUSE_ENTERED : BC
MOUSE_EXITED : BC

任何人都知道为什么会出现这个错误?

谢谢:)

3 个答案:

答案 0 :(得分:1)

不是标签引起的眨眼效果?
显示标签时,表示您退出了已侦听的节点。这会导致隐藏标签。当标签消失时,它会在节点上触发鼠标输入事件,它会显示标签等 没有经过测试,只是一个想法。


编辑:
如果我是对的,请尽量避免在鼠标指针下放置标签:

caption.setTranslateX(e.getX()+10);
caption.setTranslateY(e.getY()+10);

例如(10是幻数,取决于插图等)。

答案 1 :(得分:1)

感谢大家的帮助。

@maskacovnik找到问题,@ James_D找到一个很酷的解决方案,@ ItachiUchiha将我的图片放在我的帖子上:D

现在,我的新代码。

import java.util.ArrayList;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import com.alpha.client.view.nodes.stats.statsEngine.beans.ListRepere;
import com.alpha.client.view.nodes.stats.statsEngine.beans.OptionsChart;
import com.alpha.client.view.nodes.stats.statsEngine.beans.ValueStat;

public class PieChartNode implements ChartNode {

    //My personnal attributes
    private ListRepere categories;
    private ArrayList<ValueStat> values;
    //The PieChart
    private PieChart chart;

    //The data of Chart, will be fill by a thread
    private ObservableList<PieChart.Data> pieChartData;
    //The node which contain chart and label
    private Group group;
    //The Label 
    private final Label caption;

    public PieChartNode(ListRepere categories, ArrayList<ValueStat> values, OptionsChart optionsChart) {
        this.categories = categories;
        this.values = values;

        //New Group
        group = new Group();
        //I must use a StackPane to place Label hover Chart
        StackPane pane = new StackPane();
        group.getChildren().add(pane);

        //Init' PieChart
        pieChartData = FXCollections.observableArrayList();
        chart = new PieChart(pieChartData);
        chart.setStartAngle(180.0);
        //Add chart to StackPane
        pane.getChildren().add(chart);

        //Init Popup(Label)
        caption = new Label("");
        caption.setVisible(false);
        caption.getStyleClass().addAll("chart-line-symbol", "chart-series-line");
        caption.setStyle("-fx-font-size: 12; -fx-font-weight: bold;");
        caption.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
        //Add Label to StackPane
        pane.getChildren().add(caption);
    }

    @Override
    public Node getNodeGraph() {
        return (Node) group;
    }

    @Override
    public Task initTaskFormat() {
        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                //i and sizeOfallElements are just use for ProgressBar 
                int i = 0;
                int sizeOfallElements = values.size();
                updateProgress(i, sizeOfallElements);

                //For Each ValueStat (a Personnal pojo Class), I must create a slice 
                for (ValueStat v : values) {
                    //Create the PieChart.Data and add it to ObservableList
                    PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(), v.getDoubleValue());
                    pieChartData.add(dataTemp);

                    //At the same way that the LineChart, I add Event when mouse entered and mouse exited.
                    //When mouse entered (on the slice of PieChart)
                    dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED,
                            new EventHandler<MouseEvent>() {
                                @Override
                                public void handle(MouseEvent e) {
                                    //Set Label ignores the mouse 
                                    caption.setMouseTransparent(true);
                                    //I move Label near the mouse cursor, with a offset !
                                    caption.setTranslateX(e.getX());
                                    caption.setTranslateY(e.getY()+20);
                                    //I change text of Label
                                    caption.setText(String.valueOf(dataTemp.getPieValue()) + "\n" + dataTemp.getName());
                                    //Change the color of popup, to adapt it to slice
                                    if(caption.getStyleClass().size() == 4){
                                        caption.getStyleClass().remove(3);
                                    }
                                    caption.getStyleClass().add(dataTemp.getNode().getStyleClass().get(2));
                                    //I display Label
                                    caption.setVisible(true);
                                }
                            });
                    //Need to add a event when the mouse move hover the slice
                    //If I don't the popup stay blocked on edges of the slice.
                    dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_MOVED,
                            new EventHandler<MouseEvent>() {
                                @Override
                                public void handle(MouseEvent e) {
                                    //Keep Label near the mouse
                                    caption.setTranslateX(e.getX());
                                    caption.setTranslateY(e.getY()+20);
                                }
                            });

                    //When mouse exited (the slice of PieChart)
                    dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_EXITED,
                            new EventHandler<MouseEvent>() {
                                @Override
                                public void handle(MouseEvent e) {
                                    //I Hide Label
                                    caption.setVisible(false);
                                }
                            });
                    //Update progress
                    updateProgress(i++, sizeOfallElements);
                }
                return null;
            }
        };
        return task;
    }
}

结果如下: PieChart JavaFX with Label/Popup/Value

答案 2 :(得分:1)

我有同样的问题,但也想确保弹出窗口可以超出图表,即当文本不适合图表时它不会被切断。这是使用工具提示而不是标签的解决方案:

ListView