【发布时间】:2016-02-16 22:37:30
【问题描述】:
我有这个条形图示例,我想在其中以易于阅读的格式显示数据:
import java.text.DecimalFormat;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Tooltip;
import javafx.stage.Stage;
public class MainApp extends Application
{
private static final int MAX_DATA_POINTS = 50;
private Series series;
private Series series2;
private int xSeriesData = 0;
private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
private ConcurrentLinkedQueue<Number> dataQ2 = new ConcurrentLinkedQueue<Number>();
private ExecutorService executor;
private AddToQueue addToQueue;
private NumberAxis xAxis;
private void init(Stage primaryStage)
{
xAxis = new NumberAxis(0, MAX_DATA_POINTS, MAX_DATA_POINTS / 10);
xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(false);
NumberAxis yAxis = new NumberAxis();
yAxis.setAutoRanging(true);
//-- Chart
final AreaChart<Number, Number> sc = new AreaChart<Number, Number>(xAxis, yAxis);
sc.setAnimated(false);
sc.setCreateSymbols(false);
sc.setId("liveAreaChart");
sc.setTitle("Animated Area Chart");
//-- Chart Series
series = new AreaChart.Series<Number, Number>();
series.setName("Area Chart Series");
series2 = new AreaChart.Series<Number, Number>();
series2.setName("Area Chart Series");
sc.getData().addAll(series, series2);
xAxis.setTickLabelsVisible(false);
xAxis.setTickMarkVisible(false);
xAxis.setMinorTickVisible(false);
primaryStage.setScene(new Scene(sc));
}
@Override
public void start(Stage primaryStage) throws Exception
{
init(primaryStage);
primaryStage.show();
//-- Prepare Executor Services
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();
}
public static void main(String[] args)
{
launch(args);
}
private class AddToQueue implements Runnable
{
@Override
public void run()
{
try
{
// add a item of random data to queue
dataQ.add(randomInteger());
dataQ2.add(randomInteger());
Thread.sleep(400);
executor.execute(this);
}
catch (InterruptedException ex)
{
Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public int randomInteger()
{
int min = 100;
int max = 900000000;
int randomNum = min + (int) (Math.random() * ((max - min) + 1));
return randomNum;
}
private static String readableFileSize(long size)
{
if (size <= 0)
return "0";
final String[] units = new String[]
{
"B", "kB", "MB", "GB", "TB"
};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
//-- 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()));
Data data = new AreaChart.Data(xSeriesData++, dataQ.remove());
series.getData().add(data);
data.nodeProperty().addListener(new ChangeListener<Node>()
{
@Override
public void changed(ObservableValue<? extends Node> arg0, Node arg1,
Node arg2)
{
Tooltip t = new Tooltip(data.getYValue().toString() + '\n' + data.getXValue());
Tooltip.install(arg2, t);
data.nodeProperty().removeListener(this);
}
});
if (dataQ2.isEmpty())
break;
series2.getData().add(new AreaChart.Data(xSeriesData, dataQ2.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);
}
// remove points to keep us at no more than MAX_DATA_POINTS
if (series2.getData().size() > MAX_DATA_POINTS)
{
series2.getData().remove(0, series2.getData().size() - MAX_DATA_POINTS);
}
// update
xAxis.setLowerBound(xSeriesData - MAX_DATA_POINTS);
xAxis.setUpperBound(xSeriesData - 1);
}
}
原始值以字节为单位。基于该值,我想在将值插入图表之前使用方法readableFileSize(long size) 将值转换为字节/GB/兆字节等。问题是这个方法返回字符串。
如何重构代码以使用此方法?
PS。根据我尝试过的建议:
import java.text.DecimalFormat;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Tooltip;
import javafx.stage.Stage;
public class MainApp extends Application
{
private static final int MAX_DATA_POINTS = 50;
private Series series;
private Series series2;
private int xSeriesData = 0;
private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
private ConcurrentLinkedQueue<Number> dataQ2 = new ConcurrentLinkedQueue<Number>();
private ExecutorService executor;
private AddToQueue addToQueue;
private NumberAxis xAxis;
private NumberAxis yAxis;
private void init(Stage primaryStage)
{
xAxis = new NumberAxis(0, MAX_DATA_POINTS, MAX_DATA_POINTS / 10);
xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(false);
yAxis = new NumberAxis();
yAxis.setAutoRanging(true);
//-- Chart
final AreaChart<Number, Number> sc = new AreaChart<Number, Number>(xAxis, yAxis);
sc.setAnimated(false);
sc.setCreateSymbols(false);
sc.setId("liveAreaChart");
sc.setTitle("Animated Area Chart");
//-- Chart Series
series = new AreaChart.Series<Number, Number>();
series.setName("Area Chart Series");
series2 = new AreaChart.Series<Number, Number>();
series2.setName("Area Chart Series");
sc.getData().addAll(series, series2);
xAxis.setTickLabelsVisible(false);
xAxis.setTickMarkVisible(false);
xAxis.setMinorTickVisible(false);
primaryStage.setScene(new Scene(sc));
}
@Override
public void start(Stage primaryStage) throws Exception
{
init(primaryStage);
primaryStage.show();
//-- Prepare Executor Services
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();
}
public static void main(String[] args)
{
launch(args);
}
private class AddToQueue implements Runnable
{
@Override
public void run()
{
try
{
int size = randomInteger();
final String[] units = new String[]
{
"B", "kB", "MB", "GB", "TB"
};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
Long valueOf = Long.valueOf(new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)));
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis)
{
@Override
public String toString(Number object)
{
return String.format("%6.4f " + units[digitGroups], object);
}
});
// add a item of random data to queue
dataQ.add(valueOf);
dataQ2.add(randomInteger());
Thread.sleep(400);
executor.execute(this);
}
catch (InterruptedException ex)
{
Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public int randomInteger()
{
int min = 100;
int max = 900000000;
int randomNum = min + (int) (Math.random() * ((max - min) + 1));
return randomNum;
}
private static String readableFileSize(long size)
{
if (size <= 0)
return "0";
final String[] units = new String[]
{
"B", "kB", "MB", "GB", "TB"
};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
//-- 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()));
Data data = new AreaChart.Data(xSeriesData++, dataQ.remove());
series.getData().add(data);
data.nodeProperty().addListener(new ChangeListener<Node>()
{
@Override
public void changed(ObservableValue<? extends Node> arg0, Node arg1,
Node arg2)
{
Tooltip t = new Tooltip(data.getYValue().toString() + '\n' + data.getXValue());
Tooltip.install(arg2, t);
data.nodeProperty().removeListener(this);
}
});
if (dataQ2.isEmpty())
break;
series2.getData().add(new AreaChart.Data(xSeriesData, dataQ2.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);
}
// remove points to keep us at no more than MAX_DATA_POINTS
if (series2.getData().size() > MAX_DATA_POINTS)
{
series2.getData().remove(0, series2.getData().size() - MAX_DATA_POINTS);
}
// update
xAxis.setLowerBound(xSeriesData - MAX_DATA_POINTS);
xAxis.setUpperBound(xSeriesData - 1);
}
}
【问题讨论】:
-
@James_D:如果你在 cmets 中写下答案,这个问题将永远没有答案。没有人会写出正确的答案,因为这将是您评论的副本。此外,每个自愿帮助他人的人都在浪费时间研究这个问题,只是为了发现已经有了答案;-)
-
我创建了示例,但是当我尝试运行它时出现错误:
java.lang.NumberFormatException: For input string: "615.2" -
@Roland 是的,很公平。没有时间撰写完整的答案(仍然没有)。如果您愿意,请随意写一个完整的答案。
-
@James_D:您给出的答案数量可以理解。会的。