JavaFX to create bar graph
Coursework: Bar Charts
In this coursework you must design, implement, test and document an application in Java to display bar charts. Your application must feature a graphical user interface.
You must write classes for a NetBeansproject that uses JavaFXto create a graphical user interface. You must design, implement, test and document a program in Java that fulfils all the functional requirements (FR) and all the non‐functional requirements (NFR) indicated below.
You must document all of this in a report. The report must include neatly formatted copies of your Java source and evidence of your testing, including screen images from your running program.
In your report you must reflect honestly on the degree of success you have achieved.
The marking will be done on the basis of your report alone. It must not be necessary for the marker to investigate your program files.
Functional Requirements
- FR1 None of the panes in your interface should be resizable.
- FR2 The program must create a pane that is functionally equivalent to (but not necessarily identical to) that of Figure 1. (See section headed Figures)
The following functional requirements pertain to the option: Generate Bar chart.
- FR3 The program must allow the user to input text to the fields labelled Title, X‐Axis label and Y‐Axis label. This is illustrated in Figure 2.
- FR4 The values input to the text fields labelled Title, X‐Axis label and Y‐Axis label must be read by the program and used to annotate the charts it creates.
- FR5 The program must allow the user to click on the check boxes headed Enabled in the figures. In Figure 1 the topmost of these is already enabled.
- FR6 Clicking on a check box must make the corresponding text fields alongside it, headed Item Name and Value, become available for user input.
- FR7 The program must allow the user to input text to the fields labelled Item Name and Value. See Figure 3.
- FR8 The program must read the values input to the text fields labelled Item Name and Value. See Figure 3.
- FR9 If the user now clicks on the button labelled Generate Bar Chart, the program must use the values that have been entered into the text fields labelled Item Name and Value to create a bar chart. The axes of the chart must be scaled suitably to make the chart fit the pane. See Figure 4.
There is no particular significance to the colours used in this or any other of the charts.
The following functional requirements pertain to the option: Generate From CSV.
- FR10 If the user clicks on the button labelled Generate From CSV (without needing to enable any check boxes or input any text) the program must present the user with a means of selecting an existing file in comma‐separated‐value format (csv) and must then create a bar chart from the values held in the file. See Figure 5.
- FR11 If the file cannot be found, or is not in the correct format, the program must indicate an error by some means that is visible to the user. As an example, Figure 6 shows how this can be achieved for a variant of the file csv that has “xxx” in the cell for Tesco’s market share, where there should be a number.
Non‐functional Requirements
- NFR1 The program must be written in Java.
- NFR2 The graphical user interface must be created using JavaFX.
- NFR3 The code produced must respect standard Java naming conventions for classes, variables, and methods and must also respect the Java programming guidelines for this module. See the Java Conventions and Programming Guidelines document on this module’s Moodle site.
- NFR4 The code must make appropriate use of object‐oriented programming concepts.
- NFR5 The code must make appropriate use of exception‐handling features.
- NFR6 Your code must be easy to understand, and no more complicated than is necessary. See Java Conventions and Programming Guidelines.
- NFR7 Your code must be economical and not unduly repetitive. You must make appropriate use of loops and methods to avoid unnecessary repetition of code.
- NFR8 Your program must use anonymous classes or lambda expressions for handling button‐press events.
Data
Supermarket Market Share,Share (%),Supermarket
Tesco,28
Sainsbury’s,17
Asda,16
Morrisons,12
Co-op,7
Aldi,6.5
Waitrose,5.5
Lidl,5
Iceland,3
Solution
BarChartItem.java
packagebarchartsfx;
classBarChartItem
{
private String Name;
private Double Value;
BarChartItem(String name, Double value)
{
Name = name;
Value = value;
}
String getName()
{
return Name;
}
Double getValue()
{
return Value;
}
}
BarCharts.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
packagebarchartsfx;
importjavafx.application.Application;
importjavafx.fxml.FXMLLoader;
importjavafx.scene.Parent;
importjavafx.scene.Scene;
importjavafx.stage.Stage;
/**
*
* @author Oleg
*/
public class BarCharts extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource(“FXMLDocument.fxml”));
Scene scene = new Scene(root);
stage.setTitle(“Bar Chart Generator”);
stage.setScene(scene);
stage.show();
}
/**
* @paramargs the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
BarChartsFX.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
packagebarchartsfx;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileNotFoundException;
importjava.io.FileReader;
importjava.io.IOException;
importjava.util.ArrayList;
importjava.util.logging.Level;
importjava.util.logging.Logger;
importjavafx.application.Application;
importjavafx.event.ActionEvent;
importjavafx.event.EventHandler;
importjavafx.geometry.Insets;
importjavafx.geometry.Pos;
importjavafx.scene.Scene;
importjavafx.scene.control.Button;
importjavafx.scene.control.CheckBox;
importjavafx.scene.control.Label;
importjavafx.scene.control.TextField;
importjavafx.scene.layout.AnchorPane;
importjavafx.scene.layout.GridPane;
importjavafx.stage.FileChooser;
importjavafx.stage.FileChooser.ExtensionFilter;
importjavafx.stage.Stage;
public class BarChartsFX extends Application {
privateTextFieldtextFieldTitle;
privateTextFieldtextFieldXAxis;
privateTextFieldtextFieldYAxis;
privateArrayList<TextField>textFieldsName;
privateArrayList<TextField>textFieldsValue;
privateArrayList<CheckBox>checkboxesEnabled;
private Label labelErrorPlaceHolder;
BarChartToolbarChartTool;
@Override
public void start(Stage primaryStage) {
Label labelTitle = new Label();
labelTitle.setLayoutX(14.0);
labelTitle.setLayoutY(14.0);
labelTitle.setText(“Title:”);
textFieldTitle = new TextField();
textFieldTitle.setLayoutX(97.0);
textFieldTitle.setLayoutY(10.0);
textFieldTitle.setPromptText(“Title”);
Label labelXAxis = new Label();
labelXAxis.setLayoutX(14.0);
labelXAxis.setLayoutY(44.0);
labelXAxis.setText(“X-Axis Label:”);
Label labelYAxis = new Label();
labelYAxis.setLayoutX(14.0);
labelYAxis.setLayoutY(72.0);
labelYAxis.setText(“Y-Axis Label:”);
textFieldXAxis = new TextField();
textFieldXAxis.setLayoutX(97.0);
textFieldXAxis.setLayoutY(40.0);
textFieldXAxis.setPromptText(“Description of Items”);
textFieldYAxis = new TextField();
textFieldYAxis.setLayoutX(97.0);
textFieldYAxis.setLayoutY(68.0);
textFieldYAxis.setPromptText(“Description of Item Value”);
Button buttonGenerate = new Button();
buttonGenerate.setLayoutX(9.0);
buttonGenerate.setLayoutY(108.0);
buttonGenerate.setPrefWidth(238);
buttonGenerate.setPrefHeight(25);
buttonGenerate.setText(“Generate Bar Chart”);
buttonGenerate.setOnAction(e ->handleGenerateButtonClick());
Button buttonGenerateCSV = new Button();
buttonGenerateCSV.setLayoutX(9.0);
buttonGenerateCSV.setLayoutY(147.0);
buttonGenerateCSV.setPrefWidth(238);
buttonGenerateCSV.setPrefHeight(25);
buttonGenerateCSV.setText(“Generate From CSV”);
buttonGenerateCSV.setOnAction(e ->handleCSVButtonClick());
labelErrorPlaceHolder = new Label();
labelErrorPlaceHolder.setAlignment(Pos.TOP_LEFT);
labelErrorPlaceHolder.setLayoutX(9.0);
labelErrorPlaceHolder.setLayoutY(185.0);
labelErrorPlaceHolder.setPrefWidth(238.0);
labelErrorPlaceHolder.setPrefHeight(152.0);
AnchorPane root = new AnchorPane();
root.getChildren().add(labelTitle);
root.getChildren().add(textFieldTitle);
root.getChildren().add(labelXAxis);
root.getChildren().add(labelYAxis);
root.getChildren().add(textFieldXAxis);
root.getChildren().add(textFieldYAxis);
root.getChildren().add(buttonGenerate);
root.getChildren().add(buttonGenerateCSV);
root.getChildren().add(labelErrorPlaceHolder);
root.getChildren().add(createItemsPane());
Scene scene = new Scene(root, 494, 343);
primaryStage.setTitle(“Bar Chart Generator”);
primaryStage.setScene(scene);
primaryStage.show();
}
privateGridPanecreateItemsPane()
{
textFieldsName = new ArrayList<>();
textFieldsValue = new ArrayList<>();
checkboxesEnabled = new ArrayList<>();
GridPanegridPane = new GridPane();
gridPane.setVgap(12);
gridPane.setHgap(10);
gridPane.setLayoutX(270);
gridPane.setLayoutY(14);
gridPane.add(new Label(“Item Name”), 0, 0);
gridPane.add(new Label(“Value”), 1, 0);
gridPane.add(new Label(“Enabled”), 2, 0);
for (int i = 0; i < 10; i++)
{
TextFieldtextFieldName = new TextField();
textFieldName.setDisable(true);
textFieldName.setPrefWidth(80.0);
textFieldName.setPrefHeight(25.0);
textFieldName.setPromptText(“Item Name”);
TextFieldtextFieldValue = new TextField();
textFieldValue.setDisable(true);
textFieldValue.setPrefWidth(80.0);
textFieldValue.setPrefHeight(25.0);
textFieldValue.setPromptText(“e.g. 50”);
CheckBoxcheckBoxEnabled = new CheckBox();
checkBoxEnabled.setMnemonicParsing(false);
checkBoxEnabled.setOnAction((ActionEvent event) -> {
if (checkBoxEnabled.isSelected())
{
textFieldValue.setDisable(false);
textFieldName.setDisable(false);
}
else
{
textFieldValue.setDisable(true);
textFieldName.setDisable(true);
}
});
gridPane.add(textFieldName, 0, i + 1);
gridPane.add(textFieldValue, 1, i + 1);
gridPane.add(checkBoxEnabled, 2, i + 1);
textFieldsName.add(textFieldName);
textFieldsValue.add(textFieldValue);
checkboxesEnabled.add(checkBoxEnabled);
}
returngridPane;
}
private void handleGenerateButtonClick()
{
barChartTool = new BarChartToolImpl();
barChartTool.setName(textFieldTitle.getText());
barChartTool.setXAxisName(textFieldXAxis.getText());
barChartTool.setYAxisName(textFieldYAxis.getText());
for (int i = 0; i <checkboxesEnabled.size(); i++)
{
try
{
Double value = Double.parseDouble(
textFieldsValue.get(i).getText());
String name = textFieldsName.get(i).getText();
barChartTool.addItem(name, value);
}
catch (NumberFormatException e)
{}
}
barChartTool.show();
}
private void handleCSVButtonClick() {
FileChooserfileChooser = new FileChooser();
fileChooser.setTitle(“Open CSV File”);
fileChooser.setInitialDirectory(new java.io.File( “.” ));
fileChooser.getExtensionFilters().addAll(
newExtensionFilter(“CSV Files”, “*.csv”));
File selectedFile = fileChooser.showOpenDialog(null);
BarChartTooltempBarChart = new BarChartToolImpl();
booleandataIsCorrect = true;
if (selectedFile != null)
{
BufferedReaderbr = null;
String line = “”;
String cvsSplitBy = “,”;
try {
br = new BufferedReader(new FileReader(
selectedFile.getAbsolutePath()));
line = br.readLine();
String[] headers = line.split(cvsSplitBy);
if (headers.length< 3)
{
dataIsCorrect = false;
}
if (dataIsCorrect)
{
tempBarChart.setName(headers[0]);
tempBarChart.setYAxisName(headers[1]);
tempBarChart.setXAxisName(headers[2]);
}
while ((line = br.readLine()) != null &&dataIsCorrect)
{
// use comma as separator
String[] dataPair = line.split(cvsSplitBy);
if (dataPair.length != 2)
{
dataIsCorrect = false;
break;
}
Double value;
try
{
value = Double.parseDouble(dataPair[1]);
tempBarChart.addItem(dataPair[0], value);
}
catch (NumberFormatException e)
{
dataIsCorrect = false;
}
}
}
catch (FileNotFoundException e)
{
dataIsCorrect = false;
e.printStackTrace();
}
catch (IOException e)
{
dataIsCorrect = false;
e.printStackTrace();
}
finally
{
if (br != null)
{
try
{
br.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
if (dataIsCorrect)
{
barChartTool = tempBarChart;
barChartTool.show();
}
else
{
labelErrorPlaceHolder.setText(“The file structure is not correct.”);
}
}
}
/**
* @paramargs the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
BarChartTool.java
packagebarchartsfx;
public interface BarChartTool
{
voidsetName(String name);
voidsetXAxisName(String name);
voidsetYAxisName(String name);
voidaddItem(String name, Double value);
void show();
}
BarChartToolImpl.java
packagebarchartsfx;
importjava.util.ArrayList;
importjavafx.scene.Scene;
importjavafx.scene.chart.BarChart;
importjavafx.scene.chart.CategoryAxis;
importjavafx.scene.chart.NumberAxis;
importjavafx.scene.chart.XYChart;
importjavafx.stage.Stage;
public class BarChartToolImpl implements BarChartTool
{
public String ChartName;
public String XAxisName;
public String YAxisName;
privateArrayList<BarChartItem>DataItems = new ArrayList<BarChartItem>();
private Stage stage;
public void setName(String name)
{
ChartName = name;
}
public void setXAxisName(String name)
{
XAxisName = name;
}
public void setYAxisName(String name)
{
YAxisName = name;
}
public void addItem(String name, Double value)
{
DataItems.add(new BarChartItem(name, value));
}
public void show()
{
finalCategoryAxisxAxis = new CategoryAxis();
finalNumberAxisyAxis = new NumberAxis();
finalBarChart<String, Number>bc =
newBarChart<String, Number>(xAxis,yAxis);
bc.setTitle(getName());
xAxis.setLabel(getXAxisName());
yAxis.setLabel(getYAxisName());
for (BarChartItembarChartItem : DataItems)
{
XYChart.Series series = new XYChart.Series();
series.getData().add(new XYChart.Data(
barChartItem.getName(), barChartItem.getValue()));
bc.getData().add(series);
}
Scene scene = new Scene(bc,800,600);
stage = new Stage();
stage.setTitle(getName());
stage.setScene(scene);
stage.show();
}
/**
* @return the ChartName
*/
public String getName() {
returnChartName;
}
/**
* @return the XAxisName
*/
public String getXAxisName() {
returnXAxisName;
}
/**
* @return the YAxisName
*/
public String getYAxisName() {
returnYAxisName;
}
publicintgetItemsCount()
{
returnDataItems.size();
}
}