Reputation: 1668
I'm working on this example with Pie chart. I want to create data dynamically and update Pie chart every time when new custom object is generated:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.PieChart.Data;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tooltip;
import javafx.scene.effect.Glow;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MainApp extends Application
{
Stage stage;
private ObservableList<Data> pieChartdData = FXCollections.observableArrayList();
private final PieChart chart = new PieChart(pieChartdData);
Label caption;
@Override
public void start(Stage stage)
{
this.stage = stage;
setUserAgentStylesheet(STYLESHEET_MODENA);
Scene scene = new Scene(new Group());
stage.setTitle("Imported Fruits");
stage.setWidth(500);
stage.setHeight(500);
chart.setTitle("Imported Fruits");
// Add some data
addPieChartData("Grapefruit", 13);
addPieChartData("Oranges", 25);
addPieChartData("Plums", 10);
addPieChartData("Pears", 22);
addPieChartData("Apples", 30);
// Some task which updates the Pie Chart
final Task task;
task = new Task<Void>()
{
@Override
protected Void call() throws Exception
{
int max = 50;
int l = 0;
for (int i = 1; i <= max; i++)
{
FSPartitions data1 = FSPartitions.newInstance().FSName("test1").FSType("test1").isReadonly(true).totalSize(3434).usedSize(333).availableSize(3644);
FSPartitions data2 = FSPartitions.newInstance().FSName("test2").FSType("test2").isReadonly(true).totalSize(34334).usedSize(343).availableSize(3544);
FSPartitions data3 = FSPartitions.newInstance().FSName("test3").FSType("test3").isReadonly(true).totalSize(34543).usedSize(353).availableSize(3446);
List<FSPartitions> ss = new ArrayList<>();
ss.add(data1);
ss.add(data2);
ss.add(data3);
updatePieChart(ss);
Thread.sleep(600);
}
return null;
}
};
new Thread(task).start();
((Group) scene.getRoot()).getChildren().addAll(chart, caption);
stage.setScene(scene);
stage.show();
}
public void addPieChartData(String name, double value)
{
pieChartdData.add(new Data(name, value));
caption = new Label();
caption.setTextFill(Color.DARKORANGE);
caption.setStyle("-fx-font: 24 arial;");
for (final Data data : chart.getData())
{
Node node = data.getNode();
node.addEventHandler(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>()
{
@Override
public void handle(MouseEvent e)
{
caption.setTranslateX(e.getSceneX() + 15);
caption.setTranslateY(e.getSceneY());
caption.setText(String.valueOf(data.getPieValue()) + "%");
caption.setVisible(true);
node.setEffect(new Glow());
//String styleString = "-fx-border-color: white; -fx-border-width: 1; -fx-border-style: dashed;";
//node.setStyle(styleString);
}
});
node.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>()
{
@Override
public void handle(MouseEvent e)
{
caption.setVisible(false);
node.setEffect(null);
//node.setStyle("");
}
});
final MenuItem resizeItem = new MenuItem("Resize");
resizeItem.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
System.out.println("Resize requested");
}
});
final MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
System.out.println("About requested");
}
});
final MenuItem changeColorItem = new MenuItem("Change Color");
changeColorItem.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
System.out.println("change Color Item requested");
}
});
final ContextMenu menu = new ContextMenu(resizeItem, aboutItem, changeColorItem);
node.setOnMouseClicked(new EventHandler<MouseEvent>()
{
@Override
public void handle(MouseEvent event)
{
if (MouseButton.SECONDARY.equals(event.getButton()))
{
menu.show(stage, event.getScreenX(), event.getScreenY());
}
}
});
}
}
// updates existing Data-Object if name matches
public void updatePieChart(List<FSPartitions> obj)
{
for (FSPartitions obj1 : obj)
{
String fsName = obj1.getFSName();
double usedSize = obj1.getUsedSize();
for (Data d : pieChartdData)
{
if (d.getName().equals(fsName))
{
d.setPieValue(usedSize);
return;
}
}
}
pieChartdData.forEach(data
-> data.nameProperty().bind(
Bindings.concat(
data.getName(), " ", data.pieValueProperty(), " Tons"
)
)
);
for (FSPartitions obj1 : obj)
{
String fsName = obj1.getFSName();
double usedSize = obj1.getUsedSize();
pieChartdData.add(new Data(fsName, usedSize));
}
chart.getData().stream().forEach(data ->
{
Tooltip aaas = new Tooltip();
aaas.setText(data.getPieValue() + "%");
Tooltip.install(chart, aaas);
data.pieValueProperty().addListener((observable, oldValue, newValue)
-> aaas.setText(newValue + "%"));
});
chart.setData(pieChartdData);
}
public static void main(String[] args)
{
launch(args);
}
}
class FSPartitions implements Serializable
{
private static final long serialVersionUID = 1L;
private String FSName;
private String FSType;
private boolean isReadonly;
private long totalSize;
private long usedSize;
private long availableSize;
public static FSPartitions newInstance()
{
return new FSPartitions();
}
public FSPartitions()
{
}
@Override
public String toString()
{
return "FSName=" + FSName + ", FSType=" + FSType + ", totalSize=" + totalSize + ", usedSize=" + usedSize + ", availableSize=" + availableSize;
}
public FSPartitions FSName(String FSName)
{
this.FSName = FSName;
return this;
}
public FSPartitions FSType(String FSType)
{
this.FSType = FSType;
return this;
}
public FSPartitions isReadonly(boolean isReadonly)
{
this.isReadonly = isReadonly;
return this;
}
public FSPartitions totalSize(long totalSize)
{
this.totalSize = totalSize;
return this;
}
public FSPartitions usedSize(long usedSize)
{
this.usedSize = usedSize;
return this;
}
public FSPartitions availableSize(long availableSize)
{
this.availableSize = availableSize;
return this;
}
public String getFSName()
{
return FSName;
}
public String getFSType()
{
return FSType;
}
public boolean getIsReadonly()
{
return isReadonly;
}
public long getTotalSize()
{
return totalSize;
}
public long getUsedSize()
{
return usedSize;
}
public long getAvailableSize()
{
return availableSize;
}
}
I also want to add some additional labels for pie chart slice. Looks like I need to totally redesign the code because every time I will have different data and I need to to visualize the data. How I can to this? Can you help me to implement this?
Upvotes: 1
Views: 2267
Reputation: 5123
You can override PieChart#layoutChartChildren
to display additional values in the label of the pie chart slices. I modified your code to show an example. For adding values, I used your update thread, but modified the usedSize
values with the variable "l" to produce changing values and labels in the animation.
The FSPartitions class is missing in the below example.
public class MainApp extends Application {
Stage stage;
private ObservableList<Data> pieChartData = FXCollections.observableArrayList();
private final PieChart chart = new PieChart(pieChartData) {
@Override
protected void layoutChartChildren(double top, double left, double contentWidth, double contentHeight) {
if (getLabelsVisible()) {
getData().forEach(d -> {
Optional<Node> opTextNode = chart.lookupAll(".chart-pie-label").stream().filter(n -> n instanceof Text && ((Text) n).getText().contains(d.getName())).findAny();
if (opTextNode.isPresent()) {
((Text) opTextNode.get()).setText(d.getName() + " " + d.getPieValue());
}
});
}
super.layoutChartChildren(top, left, contentWidth, contentHeight);
}};
Label caption = new Label();
@Override
public void start(Stage stage) {
this.stage = stage;
setUserAgentStylesheet(STYLESHEET_MODENA);
Scene scene = new Scene(new Group());
stage.setTitle("File System");
stage.setWidth(500);
stage.setHeight(500);
chart.setTitle("File System Size");
// Some task which updates the Pie Chart
final Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
int max = 50;
int l = 0;
for (int i = 1; i <= max; i++) {
FSPartitions data1 = FSPartitions.newInstance().FSName("test1").FSType("test1").isReadonly(true).totalSize(3434).usedSize(333+l).availableSize(3644);
FSPartitions data2 = FSPartitions.newInstance().FSName("test2").FSType("test2").isReadonly(true).totalSize(34334).usedSize(343+(2*l)).availableSize(3544);
FSPartitions data3 = FSPartitions.newInstance().FSName("test3").FSType("test3").isReadonly(true).totalSize(34543).usedSize(353+3*l).availableSize(3446);
l++;
List<FSPartitions> ss = new ArrayList<>();
ss.add(data1);
ss.add(data2);
ss.add(data3);
updatePieChart(ss);
Thread.sleep(600);
}
return null;
}
};
new Thread(task).start();
((Group) scene.getRoot()).getChildren().addAll(chart, caption);
stage.setScene(scene);
stage.show();
}
public void addPieChartData(String name, double value) {
pieChartData.add(new Data(name, value));
caption = new Label();
caption.setTextFill(Color.DARKORANGE);
caption.setStyle("-fx-font: 24 arial;");
for (final Data data : chart.getData()) {
Node node = data.getNode();
node.addEventHandler(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
caption.setTranslateX(e.getSceneX() + 15);
caption.setTranslateY(e.getSceneY());
caption.setText(String.valueOf(data.getPieValue()) + "%");
caption.setVisible(true);
node.setEffect(new Glow());
// String styleString = "-fx-border-color: white;
// -fx-border-width: 1; -fx-border-style: dashed;";
// node.setStyle(styleString);
}
});
node.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
caption.setVisible(false);
node.setEffect(null);
// node.setStyle("");
}
});
final MenuItem resizeItem = new MenuItem("Resize");
resizeItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Resize requested");
}
});
final MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("About requested");
}
});
final MenuItem changeColorItem = new MenuItem("Change Color");
changeColorItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("change Color Item requested");
}
});
final ContextMenu menu = new ContextMenu(resizeItem, aboutItem, changeColorItem);
node.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (MouseButton.SECONDARY.equals(event.getButton())) {
menu.show(stage, event.getScreenX(), event.getScreenY());
}
}
});
}
}
// updates existing Data-Object if name matches
public void updatePieChart(List<FSPartitions> obj) {
Platform.runLater(new Runnable() {
@Override
public void run() {
for (FSPartitions obj1 : obj) {
String fsName = obj1.getFSName();
double usedSize = obj1.getUsedSize();
boolean found = false;
for (Data d : pieChartData) {
if (d.getName().equals(fsName)) {
d.setPieValue(usedSize);
found = true;
break;
}
}
if (!found) {
addPieChartData(fsName, usedSize);
}
}
}
});
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 2