JavaFX - Bind LocalTime to TableColumn via Property - java

I am using JavaFX to wrap existing classes with properties, so that I may bind them to a GUI directly without having to manually hook up events. Here is a sample of my code:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.ObjectProperty;
import controller.NewOrder;
import controller.Types.Action;
public class ObservableOrder extends NewOrder
{
private StringProperty m_account;
private ObjectProperty<Action> m_action;
public ObservableOrder()
{
// CONSTRUCT PROPERTIES
m_account = new SimpleStringProperty(this, "m_account");
m_action = new SimpleObjectProperty<Action>(this, "m_action", Action.BUY);
}
// GETTERS
#Override public String account() { return m_account.get(); }
#Override public Action action() { return m_action.get(); }
// SETTERS
#Override public void account(String v) { accountProperty().set(v); }
#Override public void action(Action v) { actionProperty().set(v); }
// PROPERTY GETTERS
public StringProperty accountProperty() { return m_account; }
public ObjectProperty<Action> actionProperty() { return m_action; }
}
This works for integers, strings and enums. What I would like to do next is wrap a LocalTime object with properties and bind it to a table column, but I can't figure it out. Should I use ObservableValue instead? Any help is appreciated. Thx

Related

Flink Java API - Pojo Type to Tuple Datatype

I am creating a small utility on JAVA flink API to learn the functionalities. I am trying to read csv file and just print it and I have developed a POJO class for the structure of the data. When I executed the code, I dont see the right values.(Integers values are replaced with zeros and null values for String. How do I map the datatype for the attributes
My Main Class:
package org.karthick.flinkLab;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import javax.xml.crypto.Data;
public class CSVFileRead {
public static void main(String[] args) throws Exception {
System.out.println("--CSV File Reader using Flink's Data Set API--");
ExecutionEnvironment execEnv = ExecutionEnvironment.getExecutionEnvironment();
DataSet<DataModel> csvInput = execEnv.readCsvFile("C:\\Flink\\Data\\IndividualDetails.csv")
.pojoType(DataModel.class);
csvInput.print();
}
}
My Pojo class (DataModel.class)
package org.karthick.flinkLab;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.api.java.tuple.Tuple12;
import java.io.Serializable;
import java.util.Date;
public class DataModel<T extends Tuple>
extends Tuple12<Integer,String,Date,Integer,String,String,String,String,String,String,Date,String>
implements Serializable
{
public Integer id;
public String government_id;
public Date diagnosed_date;
public Integer age;
public String detected_city;
public String detected_district;
public String detected_state;
public String nationality;
public String current_status;
public Date status_change_date;
public String notes;
public DataModel() {};
public String getNotes() {
return notes;
}
public Date getStatus_change_date() {
return status_change_date;
}
public String getCurrent_status() {
return current_status;
}
public String getNationality() {
return nationality;
}
public String getDetected_state() {
return detected_state;
}
public String getDetected_district() {
return detected_district;
}
public String getDetected_city() {
return detected_city;
}
public String gender ;
public Date getDiagnosed_date() {
return diagnosed_date;
}
public String getGender() {
return gender;
}
public Integer getAge() {
return age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getGovernment_id() {
return government_id;
}
public void setGovernment_id(String government_id) {
this.government_id = government_id;
}
}
When I executed the main method, I dont see the proper values. Sample result
(0,,Tue May 19 16:50:38 IST 2020,0,,,,,,,Tue May 19 16:50:38 IST 2020,)
where as I expect something like
(2777,AP,Tue May 19 16:50:38 IST 2020,0,A,B,C,D,E,F,Tue May 19 16:50:38 IST 2020,G)
What could be missing here?
You are missing the column mapping from CSV to POJO. Adding the mapping will work. The mapping of the column names must follow the following two rules:
The column names should be exactly the same names as in POJO.
The order of the columns in the mapping should be exactly the same as in the CSV file.
You can define the mapping as follows:
DataSet<DataModel> csvInput = execEnv.readCsvFile("C:\\Flink\\Data\\IndividualDetails.csv")
.pojoType(DataModel.class, "id", "age",.........);
It should have thrown error but it hasn't. It could be a bug

Create a deep copy of a Collection to a ImmutableSortedSet upon initialization of a class in java

I have an ImmutableSortedSet that is create on initialization of a class. For every object of this class i want the ImmutableSortedSet to have a deep copy (clone) of the elements stored in an Collection located in another file.
This is the collection with the original values (could also be a set)
public static final List<Quest> QUESTS = new ArrayList<>();
This is the class i want to create with the ImmutableSortedSet
package com.vencillio.rs2.content.quest;
import java.util.Optional;
import java.util.Set;
import com.google.common.collect.ImmutableSortedSet;
public class QuestManager {
private int questPoints = 0;
private final Set<Quest> QUESTS = ImmutableSortedSet.copyOf(Quest.QUESTS); //This is only a shallow copy
public int getQuestPoints() {
return questPoints;
}
public void addQuestPoints(int amount) {
questPoints += amount;
}
public void removeQuestPoints(int amount) {
questPoints -= amount;
}
public Optional<QuestState> getQuestState(String name) {
return getQuest(name).isPresent() ? Optional.of(getQuest(name).get().getQuestState()) : Optional.empty();
}
public void setQuestState(String name, QuestState state) {
if(getQuest(name).isPresent())
getQuest(name).get().setQuestState(state);
}
public Optional<Quest> getQuest(String name) {
return QUESTS.stream().filter(quest -> quest.getName().equalsIgnoreCase(name)).findAny();
}
}
You haven't explained how to get a copy of a Quest in the first place, which is an aspect of your design. In general, I'd write something like
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static java.util.Comparator.naturalOrder;
Quest.QUESTS.stream()
.map(quest -> copy(quest))
.collect(toImmutableSortedSet(naturalOrder()));

JavaFX bind choicebox to a property in a collection

With JavaFX, what is the best way to bind ChoiceBox to properties of a collection?
In example below I try to bind ChoiceBox elements to name of an ObservableList beans. This works fine when items are added/removed but not when the property value name change.
I was hoping there is a clean and simple solution to this but haven't yet found any example of it...
The class ExampleBean2 in deliberately not implemented with properties since that object may correspond to a external model class out of my control.
package com.playground;
import org.controlsfx.control.PropertySheet;
import org.controlsfx.property.BeanPropertyUtils;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class BindingPlayGround extends Application{
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("FXPlayGround");
Parent content = createContentPane();
Scene scene = new Scene(content, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
protected Parent createContentPane() {
ObservableList<BeanExample2> beans = FXCollections.observableArrayList();
ObservableList<PropertySheet> sheets = FXCollections.observableArrayList();
ListView<PropertySheet> listView = new ListView<PropertySheet>(sheets);
Button addBeanButton = new Button("Add Bean");
addBeanButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
BeanExample2 e = new BeanExample2();
e.setName("Name-not-set");
PropertySheet propertySheet = new PropertySheet(BeanPropertyUtils.getProperties(e));
sheets.add(propertySheet);
beans.add(e);
}
});
VBox vBar = new VBox();
vBar.getChildren().add(listView);
vBar.getChildren().add(addBeanButton);
ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
#Override
public Observable[] call(BeanExample2 param) {
return new Observable[]{new SimpleStringProperty(param, "name")};
}
});
Bindings.bindContent(names, beans);
Button addChoiceBoxButton = new Button("Add ChoiceBox");
addChoiceBoxButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
ChoiceBox<BeanExample2> choiceBox = new ChoiceBox<BeanExample2>(names);
vBar.getChildren().add(choiceBox);
}
});
vBar.getChildren().add(addChoiceBoxButton);
return vBar;
}
static class BeanExample2 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "BeanExample2{" +
"name='" + name + '\'' +
'}';
}
}
}
Here
ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
#Override
public Observable[] call(BeanExample2 param) {
return new Observable[]{new SimpleStringProperty(param, "name")};
}
});
you're creating a new property to listen to for updates that cannot be referenced except from the value returned by the call method. The only relationship between the BeanExample2 instance and the SimpleStringProperty is that the BeanExample2 instance is used as bean for the property, which has no effect besides being available via the getBean() method of the property. The value of the property is never assigned let alone modified on a change of the BeanExample2 instance.
To properly trigger updates in the ObservableList, you need to make sure the element in the array returned by the above method is actually notified of updates. Usually you add the property to the class itself:
public static class BeanExample2 {
public final String getName() {
return this.name.get();
}
private final StringProperty name = new SimpleStringProperty();
public final void setName(String value) {
this.name.set(value);
}
#Override
public String toString() {
return "BeanExample2{"
+ "name='" + name.get() + '\''
+ '}';
}
public final StringProperty nameProperty() {
return this.name;
}
}
And return an array containing the property from the Callback
ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
#Override
public Observable[] call(BeanExample2 param) {
return new Observable[]{param.nameProperty()};
}
});
Note that currently there seems to be a bug in ChoiceBox that adds entries for every intermediate value to the ChoiceBox.
ComboBox does not have this issue and could be used instead of a ChoiceBox.

what is IntegerProperty and why does it need to be imported

So in class we always use the following syntax. Correct me if i am wrong but this is a bean because it class use getters/setters. It has an nullary constructor and the class implements serializable.
// option 1
private int customerID ;
public CustomerDTO ()
{
this(0);
}
public CustomerDTO(int customerID) {
setCustomerID(customerID);
}
public void setCustomerID(int customerID) {
this.customerID = customerID;
}
public int getCustomerID() {
return customerID;
}
But today i came across something similar like this. i needed to import
import javafx.beans.property.SimpleStringProperty;
But what is the main difference between option 1 and 2.
When should i use option 1 or option 2
And which one is better or does it depends on the situation.
// option 2
private final IntegerProperty customerID;
public CustomerDTO ()
{
this(null);
}
public CustomerDTO(IntegerProperty customerID) {
this.customerID = new SimpleIntegerProperty();
}
public IntegerProperty getCustomerID() {
return customerID;
}
public void setCustomerID(int customerID) {
this.customerID.set(customerID);
}
Option 2 is used when you are building JavaFX application and want to bind your model with gui.
Example:
public class Foo {
private final StringProperty foo = new SimpleStringProperty();
public String getFoo() {
return foo.get();
}
public StringProperty fooProperty() {
return foo;
}
public void setFoo(String foo) {
this.foo.set(foo);
}
}
public class FooController {
#FXML
private TextField fooTextField;
private final Foo foo = new Foo();
#FXML
public void initialize() {
foo.fooProperty().bindBidirectional(fooTextField.textProperty());
}
}
public CustomerDTO(IntegerProperty customerID) { makes no sense, a property is a final class member which encapsulates a value, this value can be set via setters and get via setters, in JavaFX controller classes it is advisable to also implement a getter for the ReadOnlyObjectProperty or ReadOnlyIntegerProperty in your case, this can be done via ReadOnlyIntegerWrapper and its getReadOnlyProperty method. This enables the developor to bind to values from other classes whilst also ensuring that the value exists at any time, JavaFX Bindings are a pretty elegant and object-oriented method of data-encapsulation.
Your "option 2" actually is flawed since it allows property-redefinition which breaks this concept and makes the property itself useless. It will also break GUI functionality except if the property itself can not be redefined, see the accepted answer

Getting the next time in a Java List

My logic is eluding me on this one, I'm hoping someone has some code I can learn from.
In java I have a List of custom objects, one of the members of this object is date/time of a certain event.
I need to be able to find the next time in the List from the current/local time.
Ie, The local time is 6pm
The list contains:
1pm, 3pm, 4pm, 7pm, 10pm
I need a method to basically pull out 7pm, as the next event time to process.
Any suggestions, directions appreciated, thx
You can do it by assuming the first dateTime object in the list to be the closest initially and then iterating to find if any other dateTime from the list is more closer to your refernce dateTime.Something like this:
import java.util.ArrayList;
import java.util.List;
import org.joda.time.DateTime;
public class test {
public static void main(String[] args) {
CustomData cd1 = new CustomData("data1", new DateTime(100000));
CustomData cd2 = new CustomData("data2", new DateTime(200000));
CustomData cd3 = new CustomData("data3", new DateTime(300000));
CustomData cd4 = new CustomData("data4", new DateTime(400000));
List<CustomData> dataList = new ArrayList<CustomData>();
dataList.add(cd1);
dataList.add(cd2);
dataList.add(cd3);
dataList.add(cd4);
DateTime closestDate=dataList.get(0).getDateTime(); //initially assume first dateTime to be the closest
for(CustomData cd:dataList){
if(cd!=null && cd.getDateTime()!=null && cd.getDateTime().isBefore(closestDate.getMillis()) && cd.getDateTime().isAfter(DateTime.now())){
/*if the date time is before the closest date and after the reference DateTime you are comparing(in this case DateTime.now()) update the reference of closestDate */
closestDate=cd.getDateTime();
}
}
System.out.println(closestDate);
}
}
Also for reference the CustomData class:
import org.joda.time.DateTime;
public class CustomData {
private String name;
private DateTime dateTime;
public CustomData(String name, DateTime dateTime) {
this.name = name;
this.dateTime = dateTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DateTime getDateTime() {
return dateTime;
}
public void setDateTime(DateTime dateTime) {
this.dateTime = dateTime;
}
}
Assuming that:
You have a class Event which has a time property,
the time property is of type java.time.LocalTime or something else which either has a natural order (like java.util.Date) or for which you can easily provide a Comparator,
you have your events in a java.util.List<Event> which is unsorted,
your class Event defines a natural order according to time (implements Comparable<Event>) or you provide a Comparator<Event> which compares Event objects by their time property,
basically the relevant essentials of class Event being this,
import java.time.LocalTime;
public class Event implements Comparable<Event> {
LocalTime time;
#Override
public int compareTo(final Event o) {
return time.compareTo(o.time);
}
}
or
import java.time.LocalTime;
public class Event {
LocalTime time;
public static final Comparator<Event> byTime = new Comparator<Event>() {
#Override
public int compare(final Event o1, final Event o2) {
return o1.time.compareTo(o2.time);
}
};
}
then you could use one of the following ways to get the event you're looking for (and there are certainly many more ways):
You could iterate through the List with a for-each loop (comparative linear search).
You could stream() your list, filter() all events after that time, sort() them, and take the first.
You could put the events in a TreeMap<LocalTime, Event> and ask the TreeMap for the ceilingKey().
Which of these solutions is best depends on how you actually store your data. If access on List<Event> is frequently done based on the time property, you might want to permanently keep a TreeMap<LocalTime, Event> in your application. In that case, the third solution is best. If it's done rarely, I'd use the Streams solution. The first solution is the naive primitive approach, and although we've been coding that way for decades, I don't like it.
Here are these three solutions:
public static Event getNextEventUsingComparison(final List<Event> unsortedEvents, final LocalTime timestamp) {
Event candidateEvent = null;
for (final Event event : unsortedEvents)
if (event.getTime().isAfter(timestamp) && (candidateEvent == null || event.getTime().isBefore(candidateEvent.getTime())))
candidateEvent = event;
return candidateEvent;
}
public static Event getNextEventUsingStreams(final List<Event> unsortedEvents, final LocalTime timestamp) {
return unsortedEvents.stream().filter(t -> t.getTime().isAfter(timestamp)).sorted().findFirst().orElse(null);
}
public static Event getNextEventUsingTreeMap(final List<Event> unsortedEvents, final LocalTime timestamp) {
final TreeMap<LocalTime, Event> timeEventMap = new TreeMap<>();
for (final Event event : unsortedEvents)
timeEventMap.put(event.getTime(), event);
final LocalTime key = timeEventMap.ceilingKey(timestamp);
return key != null ? timeEventMap.get(key) : null;
}
It should work just as well with other time classes like java.util.Date instead of java.time.LocalTime as long as they are implements Comparable or you can provide a Comparator.
In case you mess around with this code, you might want to test it. Here's the code relevant to testing which I used for this:
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
public class Event implements Comparable<Event> {
String title;
LocalTime time;
public Event(final String title, final LocalTime time) {
this.title = title;
this.time = time;
}
public Event(final String descriptor) {
this(descriptor.substring(6), LocalTime.parse(descriptor.substring(0, 5)));
}
public String getTitle() { return title; }
public LocalTime getTime() { return time; }
#Override
public int compareTo(final Event o) { return time.compareTo(o.time); }
public static List<Event> createEventList(final String... descriptors) {
final List<Event> events = new ArrayList<>();
for (final String descriptor : descriptors)
events.add(new Event(descriptor));
return events;
}
}
And the Unit Test:
import org.junit.Test;
import java.util.List;
import static java.time.LocalTime.of;
import static java.util.Collections.emptyList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static stackexchange.stackoverflow.q27350515.Event.createEventList;
import static stackexchange.stackoverflow.q27350515.FindNextDate.getNextEvent;
public class FindNextDateTest {
#Test public void givenEmptyList_whenFindingNext_thenReturnsNull() {
assertNull(getNextEvent(emptyList(), of(6, 0)));
}
#Test public void givenOneElementListWithSmallerElement_whenFindingNext_thenReturnsNull() {
final List<Event> events = createEventList("10:15 Breakfast");
assertNull(getNextEvent(events, of(11, 0)));
}
#Test public void givenOneElementListWithLargerElement_whenFindingNext_thenReturnsElement() {
final List<Event> events = createEventList("12:15 Lunch");
assertEquals(events.get(0), getNextEvent(events, of(11, 0)));
}
#Test public void givenBigList_whenFindingNext_thenReturnsElement() {
final List<Event> events = createEventList("10:15 Breakfast", "12:15 Lunch", "08:00 Morning walk", "11:15 Power nap", "14:00 Power nap", "20:00 Dinner");
assertEquals(events.get(3), getNextEvent(events, of(11, 0)));
}
}

Categories

Resources