I have a String containing a Date in the form "dd-MM-yyyy" I want the dates to be sorted when displayed in the table view.
Controller Class
private final ObservableList<Stock>stockList = FXCollections.observableArrayList();
public class StocksController implements Initializable {
@FXML
private TableColumn<Stock, String> date;
public void initialize(URL url, ResourceBundle resourceBundle){
addToCSV.setOnAction(event -> {
try {
writeCSV();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
dollarButton.setOnAction(event -> {changeDollar();});
percentButton.setOnAction(event -> {changePercent();});
price.setCellValueFactory(new PropertyValueFactory<>("price"));
date.setCellValueFactory(new PropertyValueFactory<>("dateRN"));
checker.setCellValueFactory(new PropertyValueFactory<>("checker"));
stockView.setItems(stockList);
search();
readCSV();
}
public void writeCSV() throws IOException {
String stockNames = ("$" stockName.getText()).trim().toUpperCase();
Double stockPrices = Double.parseDouble((stockPrice.getText()).trim());
String stockDates = stockDate.getValue().format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
FileWriter fw = new FileWriter("src/stocks.csv",true);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw);
pw.println(stockNames ',' stockDates ',' stockPrices);
pw.flush();
pw.close();
stockList.clear();
readCSV();
}
public void readCSV(){
String csv;
csv = "src/stocks.csv";
String delimiter = ",";
try{
System.out.println(new FileReader(csv));
BufferedReader br = new BufferedReader(new FileReader(csv));
String line;
while((line = br.readLine()) != null) {
String[] values = line.split(delimiter);
String stockNames = values[0];
String stockDates = values[1];
Double stockPrices = Double.parseDouble(values[2]);
Stock stock = new Stock(stockNames, stockPrices,stockDates);
stockList.add(stock);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(StocksController.class.getName())
.log(Level.FINE, null, ex);
} catch (IOException ex) {
Logger.getLogger(StocksController.class.getName())
.log(Level.FINE, null, ex);
}
}
}
Stock Class
public class Stock {
private String dateRN;
public Stock(){
this.dateRN = "";
}
public Stock(String ticker, Double price, String dateRN){
this.ticker = ticker;
this.price = price;
this.dateRN = dateRN;
this.checker = new CheckBox();
}
public String getDateRN() {
return dateRN;
}
public void setDateRN(String dateRN) {
this.dateRN = dateRN;
}
}
I've tried creating a comparator for Stock but it's not working so I gave up on that method is there anyway I could just create a function inside my controller sorting it directly from the observableList itself? or even when I read in the CSV?
CodePudding user response:
The application class, StockTable
import java.net.URL;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class StockTable extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
URL url = getClass().getResource("stoktabl.fxml");
FXMLLoader loader = new FXMLLoader(url);
BorderPane root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
}
The FXML file, stoktabl.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="jfxtests.StocksController">
<center>
<TableView fx:id="table">
<columns>
<TableColumn fx:id="dateColumn" text="Date">
</TableColumn>
<TableColumn fx:id="priceColumn" text="Price">
</TableColumn>
<TableColumn fx:id="checkBoxColumn" text="Check Box">
</TableColumn>
</columns>
</TableView>
</center>
</BorderPane>
FXML controller class, StocksController
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.StringConverter;
public class StocksController extends StringConverter<LocalDate> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy", Locale.ENGLISH);
private static final String DELIMITER = ",";
@FXML
TableColumn<Stock, Boolean> checkBoxColumn;
@FXML
TableColumn<Stock, LocalDate> dateColumn;
@FXML
TableColumn<Stock, BigDecimal> priceColumn;
@FXML
TableView<Stock> table;
@Override // javafx.util.StringConverter
public String toString(LocalDate object) {
return object.format(FORMATTER);
}
@Override // javafx.util.StringConverter
public LocalDate fromString(String string) {
return LocalDate.parse(string, FORMATTER);
}
@FXML
private void initialize() {
table.setEditable(true);
checkBoxColumn.setCellValueFactory(f -> f.getValue().checkedProperty());
checkBoxColumn.setCellFactory(CheckBoxTableCell.forTableColumn(checkBoxColumn));
dateColumn.setCellValueFactory(f -> f.getValue().dateProperty());
dateColumn.setCellFactory(TextFieldTableCell.forTableColumn(this));
priceColumn.setCellValueFactory(f -> f.getValue().priceProperty());
ObservableList<Stock> items = FXCollections.observableArrayList();
InputStream is = getClass().getResourceAsStream("stocks.csv");
try (InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr)) {
String line = br.readLine();
while (line != null) {
String[] fields = line.split(DELIMITER);
BigDecimal price = new BigDecimal(fields[2]);
LocalDate date = LocalDate.parse(fields[1], FORMATTER);
String name = fields[0];
Stock stock = new Stock(price, date, name);
items.add(stock);
line = br.readLine();
}
items = items.sorted();
table.setItems(items);
}
catch (IOException xIo) {
throw new RuntimeException(xIo);
}
}
}
The "model" class, Stock
import java.math.BigDecimal;
import java.time.LocalDate;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
public class Stock implements Comparable<Stock> {
private SimpleObjectProperty<BigDecimal> price;
private SimpleBooleanProperty checked;
private SimpleObjectProperty<LocalDate> date;
private SimpleStringProperty name;
public Stock(BigDecimal price, LocalDate date, String name) {
this.price = new SimpleObjectProperty<BigDecimal>(this, "price", price);
this.date = new SimpleObjectProperty<LocalDate>(this, "date", date);
this.name = new SimpleStringProperty(this, "name", name);
checked = new SimpleBooleanProperty(false);
}
public SimpleBooleanProperty checkedProperty() {
return checked;
}
public boolean getChecked() {
return checked.get();
}
public void setChecked(boolean check) {
checked.set(check);
}
public SimpleObjectProperty<LocalDate> dateProperty() {
return date;
}
public LocalDate getDate() {
return date.get();
}
public void setDate(LocalDate ld) {
date.set(ld);
}
public SimpleStringProperty nameProperty() {
return name;
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public SimpleObjectProperty<BigDecimal> priceProperty() {
return price;
}
public BigDecimal getPrice() {
return price.get();
}
public void setPrice(BigDecimal cost) {
price.set(cost);
}
@Override
public int compareTo(Stock o) {
int result;
if (o == null) {
result = 1;
}
else {
if (o.date == null) {
result = 1;
}
else {
if (o.date.get() == null) {
result = 1;
}
else {
if (date == null) {
result = -1;
}
else {
if (date.get() == null) {
result = -1;
}
else {
if (date.get().isBefore(o.date.get())) {
result = -1;
}
else if (date.get().isAfter(o.date.get())) {
result = 1;
}
else {
result = 0;
}
}
}
}
}
}
return result;
}
}
The CSV file, stocks.csv
first,05-08-2022,1.22
second,03-08-2022,1.35
third,07-08-2022,67.0
last,06-08-2022,4.5
- Class
Stock
implements comparable to allowitems
to be sorted by natural order. Refer to [default] methodsorted
in interfacejavafx.collections.ObservableList
. - The
TableView
is made editable so as to allow selecting the check boxes. - Values are read from the CSV file and converted to the appropriate type in order to create
Stock
instances. - A
StringConverter
is used to both format and parse values in thedate
column. - Files
stoktabl.fxml
andstocks.csv
are located in the same folder as fileStockTable.class
- All above [Java] classes are in the same package (even though I omitted the package statements from the above code.
- Controller classes no longer need to implement interface
javafx.fxml.Initializable
. They may, optionally, declare methodinitialize
that takes no parameters and returnsvoid
.
Here is a screen capture:
CodePudding user response:
As it has been pointed out in the comments, I second @dan1st's suggestion of using a LocalDate
instead of a plain String
to represent a date and order your Stock
instances according to their dateRN
.
However, If for some reason you're actually bound to a String
implementation, then you could resort to a LocalDate
conversion within the compareTo
definition and still implement the Comparable
interface in your Stock
class.
Here is a rough implementation:
public class Stock implements Comparable<Stock> {
private String ticker;
private Double price;
private String dateRN;
public Stock() {
this.dateRN = "";
}
public Stock(String ticker, Double price, String dateRN) {
this.ticker = ticker;
this.price = price;
this.dateRN = dateRN;
}
//... getters, setters & rest of class implementation
@Override
public int compareTo(Stock o) {
return LocalDate.parse(dateRN, DateTimeFormatter.ofPattern("dd-MM-yyyy")).compareTo(LocalDate.parse(o.dateRN, DateTimeFormatter.ofPattern("dd-MM-yyyy")));
}
@Override
public String toString() {
return "Stock{dateRN='" dateRN '\'' '}';
}
}
public class Main {
public static void main(String[] args) {
List<Stock> list = new ArrayList<>(List.of(
new Stock("test1", 1.5, "05-08-2022"),
new Stock("test2", 2.5, "03-08-2022"),
new Stock("test3", 3.5, "07-08-2022"),
new Stock("test4", 4.5, "06-08-2022")
));
System.out.println(list);
Collections.sort(list);
System.out.println("\n" list);
}
}
Here is a link to test the code above:
https://www.jdoodle.com/iembed/v0/tLI
Output
Original and sorted output based on the sample data of your question.
[Stock{dateRN='05-08-2022'}, Stock{dateRN='03-08-2022'}, Stock{dateRN='07-08-2022'}, Stock{dateRN='06-08-2022'}]
[Stock{dateRN='03-08-2022'}, Stock{dateRN='05-08-2022'}, Stock{dateRN='06-08-2022'}, Stock{dateRN='07-08-2022'}]