Javafx 停止任务,如果它';它不可见

Javafx 停止任务,如果它';它不可见,javafx,javafx-2,javafx-8,Javafx,Javafx 2,Javafx 8,我有一个JavaFX任务,用于更新图表: public class LiveRAMPerformance { private static final int MAX_DATA_POINTS = 50; private Series series; private int xSeriesData = 0; private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue&

我有一个JavaFX任务,用于更新图表:

public class LiveRAMPerformance
{

    private static final int MAX_DATA_POINTS = 50;

    private Series series;
    private int xSeriesData = 0;
    private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
    private ExecutorService executor;
    private AddToQueue addToQueue;
    //private Timeline timeline2;
    private NumberAxis xAxis;

        public AreaChart<Number, Number> init()
    {
        xAxis = new NumberAxis(0, MAX_DATA_POINTS, MAX_DATA_POINTS / 10);
        xAxis.setForceZeroInRange(false);
        xAxis.setAutoRanging(false);

        xAxis.setTickLabelsVisible(false);
        xAxis.setTickMarkVisible(false);
        xAxis.setMinorTickVisible(false);

        NumberAxis yAxis = new NumberAxis();
        yAxis.setAutoRanging(true);

        //-- Chart
        final AreaChart<Number, Number> sc = new AreaChart<Number, Number>(xAxis, yAxis)
        {
            // Override to remove symbols on each data point
            @Override
            protected void dataItemAdded(Series<Number, Number> series, int itemIndex, Data<Number, Number> item)
            {
            }
        };
        sc.setAnimated(false);
        sc.setId("liveAreaChart");
        sc.setTitle("Animated Area Chart");

        //-- Chart Series
        series = new AreaChart.Series<Number, Number>();
        series.setName("Area Chart Series");
        sc.getData().add(series);

        // look up first series fill
        Node node = sc.lookup(".default-color0.chart-series-area-fill");
        // set the first series fill to translucent pale green
        node.setStyle("-fx-fill: linear-gradient(#f2f2f2, #d4d4d4);"
            + "  -fx-background-insets: 0 0 -1 0, 0, 1, 2;"
            + "  -fx-background-radius: 3px, 3px, 2px, 1px;");

        Node nodew = sc.lookup(".chart-series-area-line");
        // set the first series fill to translucent pale green
        nodew.setStyle("-fx-stroke: #989898; -fx-stroke-width: 1px; ");

        executor = Executors.newCachedThreadPool(new ThreadFactory()
        {
            @Override
            public Thread newThread(Runnable r)
            {
                Thread thread = new Thread(r);
                thread.setDaemon(true);
                return thread;
            }
        });
        addToQueue = new AddToQueue();
        executor.execute(addToQueue);
        //-- Prepare Timeline
        prepareTimeline();

        return sc;
    }

    private class AddToQueue implements Runnable
    {
        @Override
        public void run()
        {
            try
            {
                // add a item of random data to queue
                dataQ.add(Math.random());
                Thread.sleep(1150);
                executor.execute(this);
            }
            catch (InterruptedException ex)
            {
                //Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    //-- Timeline gets called in the JavaFX Main thread
    private void prepareTimeline()
    {
        // Every frame to take any data from queue and add to chart
        new AnimationTimer()
        {
            @Override
            public void handle(long now)
            {
                addDataToSeries();
            }
        }.start();
    }

    private void addDataToSeries()
    {
        for (int i = 0; i < 20; i++)
        { //-- add 20 numbers to the plot+
            if (dataQ.isEmpty())
                break;
            series.getData().add(new AreaChart.Data(xSeriesData++, dataQ.remove()));
        }
        // remove points to keep us at no more than MAX_DATA_POINTS
        if (series.getData().size() > MAX_DATA_POINTS)
        {
            series.getData().remove(0, series.getData().size() - MAX_DATA_POINTS);
        }
        // update
        xAxis.setLowerBound(xSeriesData - MAX_DATA_POINTS);
        xAxis.setUpperBound(xSeriesData - 1);
    }
}
公共级LiveRAMPerformance
{
私有静态最终整数最大数据点=50;
私人系列;
私有int xSeriesData=0;
私有ConcurrentLinkedQueue数据Q=新ConcurrentLinkedQueue();
私人遗嘱执行人;
私有AddToQueue AddToQueue;
//私人时间线2;
私人号码xis xAxis;
公共区域图初始化()
{
xAxis=新的数字轴(0,最大数据点,最大数据点/10);
xAxis.setForceZeroInRange(假);
xAxis.setAutoRanging(假);
xAxis.setTickLabelsVisible(假);
xAxis.setTickMarkVisible(false);
xAxis.setMinorTickVisible(false);
NumberAxis yAxis=新的NumberAxis();
yAxis.setAutoRanging(真);
//--图表
最终面积图sc=新面积图(X轴、Y轴)
{
//替代以删除每个数据点上的符号
@凌驾
已添加受保护的无效dataItemAdded(系列、int itemIndex、数据项)
{
}
};
sc.1(假);
sc.setId(“liveAreaChart”);
sc.setTitle(“动画面积图”);
//--图表系列
series=新的面积图。series();
系列名称(“面积图系列”);
sc.getData().add(系列);
//查找第一个系列填充
Node Node=sc.lookup(“.default-color0.图表系列区域填充”);
//将第一个系列填充设置为半透明淡绿色
node.setStyle(“-fx填充:线性渐变(#f2f2f2,#d4d4);”
+-fx背景插图:0-10,0,1,2
+“-fx背景半径:3px,3px,2px,1px;”;
节点nodew=sc.lookup(“.chart-series-area-line”);
//将第一个系列填充设置为半透明淡绿色
nodew.setStyle(“-fx笔划:#989898;-fx笔划宽度:1px;”);
executor=Executors.newCachedThreadPool(newThreadFactory())
{
@凌驾
公共线程newThread(可运行的r)
{
螺纹=新螺纹(r);
setDaemon(true);
返回线程;
}
});
addToQueue=新的addToQueue();
executor.execute(addToQueue);
//--准备时间表
制备美林();
返回sc;
}
私有类AddToQueue实现可运行
{
@凌驾
公开募捐
{
尝试
{
//将一项随机数据添加到队列
add(Math.random());
睡眠(1150);
执行人。执行(本);
}
捕获(中断异常例外)
{
//Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE,null,ex);
}
}
}
//--在JavaFX主线程中调用Timeline
私有无效制备单()
{
//从队列中获取任何数据并添加到图表的每个帧
新的AnimationTimer()
{
@凌驾
公共无效句柄(长)
{
addDataToSeries();
}
}.start();
}
私有void addDataToSeries()
{
对于(int i=0;i<20;i++)
{/--在绘图中添加20个数字+
if(dataQ.isEmpty())
打破
series.getData().add(新的AreaChart.Data(xSeriesData++,dataQ.remove());
}
//删除点以使我们保持不超过最大数据点
if(series.getData().size()>最大数据点)
{
series.getData().remove(0,series.getData().size()-最大数据点);
}
//更新
xAxis.setLowerBound(xSeriesData-最大数据点);
xAxis.setUpperBound(xSeriesData-1);
}
}
当我最小化图表或切换面板时,任务仍在运行并消耗CPU资源。如何使任务仅在用户可见时才可运行?当我发现它不可见时,我想释放资源

编辑

这可能是解决方案吗:

sc.visibleProperty().addListener(new ChangeListener<Boolean>()
        {
            @Override
            public void changed(final ObservableValue<? extends Boolean> observableValue, final Boolean aBoolean, final Boolean aBoolean2)
            {
                System.out.println("####");
                //To change body of implemented methods use File | Settings | File Templates.
            }
        });
sc.visibleProperty().addListener(新的ChangeListener())
{
@凌驾

公共无效更改(如果数据随时可用(即检索或计算不需要很长时间),则最终可观测值),那么您根本不需要所有的线程机制。只需使用
时间线
关键帧
以及更新图表的
事件处理程序
。然后,当图表从显示中移除时,您可以在
时间线
上调用
暂停()
,然后
播放()
当它可见时

Timeline timeline = new Timeline(new KeyFrame(Duration.millis(1150), 
    event -> {
        series.getData().add(new AreaChart.Data(xSeriesData++, Math.random()));
        if (series.getData().size() > MAX_DATA_POINTS) {
            series.getData().remove(0);
        }
    }));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
现在,您可以摆脱
Runnable
AnimationTimer
ConcurrentLinkedQueue
ExecutorService

因此,例如,如果您的图表位于名为
图表选项卡的
选项卡中,该选项卡位于名为
选项卡窗格的
选项卡中,您可以执行以下操作:

tabPane.getSelectionModel().selectedItemProperty().addListener((obs, oldTab, newTab) -> {
    if (newTab == chartTab) {
        timeline.play();
    } else {
        timeline.pause();
    }
});

生成数据需要很长时间吗?如果不需要,您可以使用时间线而不是任务。然后您可以调用pause()和play()根据需要。不,我只是有太多不可见的图表。我想在不可见时保存资源并禁用线程。我从服务器获取图表数据,因此需要任务或服务。我更新了帖子。我可以使用
.visibleProperty().addListener(new ChangeListener())
?不幸的是,我没有看到任何字符串
#####
。可能缺少某些内容?不,visible属性与“是否在屏幕上”不同。请阅读。是否有其他解决方案?如何获取值“是否在屏幕上”?使用任务而不是可运行的。只有在选项卡窗格中显示相应的选项卡时,才将任务重新提交给执行者。我遇到过一个案例,其中FlowPane包含多个图表。我如何确定它是否可见