Javafx tableview with data from multiple classes - java

I have no problem filling my tableview with diffrent data from 1 class. But it does not work for me with multiple classes. Any idea how to solve that?
I have checked out similar questions on stackoverflow. But none of them could help me. If you suggest anything with the "Callback" class, please provide me the full import, because there are a couple of Callback classes out there.
public class MainViewController implements Initializable {
#FXML
private TableColumn<TaskControl, Boolean> colErledigt;
#FXML
private TableColumn<TaskControl, Character> colPrioritaet;
#FXML
private TableColumn<TaskControl, String> colBeschreibung;
#FXML
private TableColumn<ProjectControl, String> colProjekt;
#FXML
private TableView<TaskControl> tblView;
public final void initialize(final URL location,
final ResourceBundle resources) {
initializeTableElements();
}
public final void initializeTableElements() {
colBeschreibung
.setCellValueFactory(new PropertyValueFactory<>("description"));
colPrioritaet
.setCellValueFactory(new PropertyValueFactory<>("priority"));
colProjekt.setCellValueFactory(new PropertyValueFactory<>("name"));
colErledigt.setMaxWidth(50);
colErledigt.setCellValueFactory(
new PropertyValueFactory<TaskControl, Boolean>("isDone"));
colErledigt
.setCellFactory(CheckBoxTableCell.forTableColumn(colErledigt));
colErledigt.setEditable(true);
try {
tblView.setItems(getObsTasks());
} catch (IDNotValidException | StringNotValidException e1) {
System.out.print("FEHLER beim getObsTasks");
}
tblView.setEditable(true);
}
public ObservableList<TaskControl> getObsTasks()
throws IDNotValidException, StringNotValidException {
ObservableList<TaskControl> obsTasks = FXCollections
.observableArrayList();
Map<Context, Set<Task>> test = TasksContextUtility.INSTANCE
.getAllContextsAndTasks();
test.values().forEach(v -> {
v.forEach(b -> obsTasks.add((TaskControl) b));
});
return obsTasks;
}
Further question: How can I show a certain Attribute of an Instance in a HashSet in a TableCell. So I have in my TaskControl class a HashSet. In that HashSet there are Instances of the class "ProjectControl". Every instance of ProjectControl has attributes like "name" or "id" etc.
And I want to represent all the names of the project instances in 1 single table cell if possible. Maybe as a string seperated with commas (project1,project2,project3...).
Task class (shortened a lot) my TaskControl Class inherits from this class
public abstract class Task
implements Serializable, IDValidatable
{
private int id;
private char priority = ' ';
private final Set<Project> projects = new HashSet();
public Task(int oid)
throws IDNotValidException
{
if (isIDValid(oid)) {
this.id = oid;
} else {
throw new IDNotValidException("The ID you have specified is not valid!")
{
private static final long serialVersionUID = 99044660889990790L;
};
}
}
public final void setId(int oid)
throws IDNotValidException
{
if (isIDValid(oid)) {
this.id = oid;
} else {
throw new IDNotValidException("The ID you have specified is not valid!")
{
private static final long serialVersionUID = 99044660889990790L;
};
}
}
public final int getId()
{
return this.id;
}
public final Collection<Context> getContexts()
{
return this.contexts;
}
public final void addContext(Context context)
throws ContextNotValidException
{
this.contexts.add(context);
}
public final void removeContext(Context context)
throws ContextNotValidException
{
this.contexts.remove(context);
}
public final Collection<Project> getProjects()
{
return this.projects;
}
public final void addProject(Project project)
throws ProjectNotValidException
{
this.projects.add(project);
}
public final void removeProject(Project project)
throws ProjectNotValidException
{
this.projects.remove(project);
}
public final Map<String, String> getAddons()
{
return this.addons;
}
}

In my opition you only have one nice solution for this.
You need a extra Class that holds your TaskControl, ContextControl and ProjectControl.
Your Code can look something like that.
class Wrapper{
private TaskControl taskControl;
private ContextControl contextControl;
private ProjectControl projectControl;
...
public Boolean isDone(){
return taskControl != null ? taskControl.isDone() : null;
}
}
#FXML
private TableView<Wrapper> tblView;
#FXML
private TableColumn<Wrapper, Boolean> colErledigt;
colErledigt.setCellValueFactory(
new PropertyValueFactory<Wrapper, Boolean>("isDone"));

Solved it by adding an additional String to my TaskControl, that contains the names of all the projects it contains. It gets the names through a function that I call just before I create the ObservableList for the Table Column.
private String projectsAsString;
...
public final void convertProjectsToString() {
String projects = "";
for (Project p : this.getProjects()) {
ProjectControl pp = (ProjectControl) p;
projects += pp.getName() + ", ";
}
if (projects != null && projects != "" && projects.length() > 4) {
projects = projects.substring(0, projects.length() - 2);
}
this.projectsAsString = projects;
}
Thank you guys anyways for helping me.

Related

returning value from async task in android

I have been trying to code an app but I am stuck with a problem. I have a function checkexistence which checks weather column with column name as the current month is present or not and another function that inserts rows in the sql database but I am not able to figure out how can use both of them to check that weather current month is present or not and if not add the current month
Here is the class with the code.
public class Repository {
private MonthDetailsDAO monthDetailsDAO;
private static Repository instance;
private YearDetailsDAO yearDetailsDAO;
private LiveData<List<MonthDetailsEntity>> liveMonthData;
private LiveData<List<YearDetailsEntity>> liveYearData;
private static final String LOG_TAG = "Database>>Repository";
public Repository(Application application){
Database database = Database.getInstance(application);
yearDetailsDAO = database.yearDetailsDAO();
liveYearData = yearDetailsDAO.getdata();
}
public void add_year(YearDetailsEntity yearDetailsEntity){
new InsertAsyncTask(yearDetailsDAO).execute(yearDetailsEntity);
}
public void checkExistance(YearDetailsEntity yearDetailsEntity){
new CheckExistanceAsyncTask(yearDetailsDAO).equals(yearDetailsEntity);
}
public LiveData<List<YearDetailsEntity>> getLiveYearData(){
return liveYearData;
}
private static class CheckExistanceAsyncTask extends AsyncTask<YearDetailsEntity , Void , Void>{
private YearDetailsDAO yearDetailsDAO;
public CheckExistanceAsyncTask(YearDetailsDAO yearDetailsDAO){
this.yearDetailsDAO = yearDetailsDAO;
}
#Override
protected Void doInBackground(YearDetailsEntity... yearDetailsEntities) {
int m = yearDetailsEntities[0].getMonth();
int y = yearDetailsEntities[0].getYear();
YearDetailsEntity yearDetailsEntity1 = yearDetailsDAO.checkExistance(m , y);
if(yearDetailsEntity1 == null) {
//insert now
}
else
Log.d(LOG_TAG , "Month already present");
return null;
}
}
private static class InsertAsyncTask extends AsyncTask<YearDetailsEntity, Void, Void> {
private YearDetailsDAO yearDetailsDAO;
public InsertAsyncTask(YearDetailsDAO yearDetailsDAO){
this.yearDetailsDAO = yearDetailsDAO;
}
#Override
protected Void doInBackground(YearDetailsEntity... yearDetailsEntities) {
yearDetailsDAO.add_year(yearDetailsEntities[0]);
return null;
}
}
}

Simple Cache mechanizm using decorators

I have a simple interface
public interface Text {
String asText() throws IOException;
}
And one implementation
public final class TextFromFile implements Text{
private final String path;
public TextFromFile(final String pth) {
this.path = pth;
}
#Override
public String asText() throws IOException {
final String text = Files.readAllLines(Paths.get(this.path))
.stream()
.collect(Collectors.joining(""));
return text;
}
}
This class is very simple, it reads text from a file then returns it as a string. In order to avoid reading from the file multiple times I want to create a second class that will decorate the original one
public final class CachedText implements Text{
private final Text origin;
private String result;
public CachedText(final Text orgn) {
this.origin = orgn;
}
#Override
public String asText() throws IOException {
if(this.result == null){
this.result = this.origin.asText();
}
return this.result;
}
}
And now it work; however the result is muttable, and in order to work correctly with multiple threads i have created another decorator
public final class ThreadSafeText implements Text{
private final Text origin;
public ThreadSafeText(final Text orgn) {
this.origin = orgn;
}
#Override
public String asText() throws IOException {
synchronized(this.origin){
return this.origin.asText();
}
}
}
But now my program will spend resources on synchronization each time I call asText() .
What is the best implementation of a caching mechanism in my situation?
I would suggest making your cached class synchronized via the Double Check Lock mechanism, instead of using the additional implementation for thread safety:
public final class CachedText implements Text{
private final Text origin;
private String result;
public CachedText(final Text orgn) {
this.origin = orgn;
}
#Override
public String asText() throws IOException {
if(this.result == null){
synchronized(this) {
if(this.result == null){
this.result = this.origin.asText();
}
}
}
return this.result;
}
}
There might be concerns using the DCL as seen here- but if they exist on your end, just comment and I'll post additional support (I believe that modern JVMs are better suited for handling DCLs).
This should be good for your needs.

Is there a "clean" way to automatically un-register a listener in Java?

I believe I've seen variants of this question, but no "definitive answer". In the code below, I understand that SomeEventManager holds a reference to someImplClassTwo.myEventListenerA and someImplClassTwo.myEventListenerB, and that this does not allow for someImplClassTwo to be garbage collected, and this results in the output generated the second time someEventManager.notifyListeners() is invoked.
But, I'd really like for users of SomeImplClass not to have to know that there are listeners involved in the implementation, and that these listeners need to be manually un-registered (i.e., SomeImplClass.releaseListeners()) before releasing the SomeImplClass object.
Is there a clean/accepted way of doing this?
p.s. I've already played with finalize(), just for fun, and confirmed that GC is not even attempted in this case, for either instance of SomeImplClass. So, that seems to be a non-starter as a potential solution.
Test Driver
public class TestDriver {
public static void main(String[] args) {
SomeEventManager someEventManager = SomeEventManager.getInstance();
SomeImplClass someImplClassOne = new SomeImplClass("One");
SomeImplClass someImplClassTwo = new SomeImplClass("Two");
someEventManager.notifyListeners();
someImplClassOne.releaseListeners();
someImplClassOne = null;
someImplClassTwo = null;
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
someEventManager.notifyListeners();
}
}
Event Interface
public interface SomeEventListener {
public void handleSomeEvent();
}
Event Manager
import java.util.ArrayList;
import java.util.List;
public class SomeEventManager {
private static SomeEventManager eventManager = null;
private List<SomeEventListener> listeners = null;
private SomeEventManager() {
listeners = new ArrayList<SomeEventListener>();
}
public static SomeEventManager getInstance() {
if (eventManager == null) {
eventManager = new SomeEventManager();
}
return eventManager;
}
public void addListener(SomeEventListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeListener(SomeEventListener listener) {
listeners.remove(listener);
}
public void notifyListeners() {
for(SomeEventListener listener : listeners) {
listener.handleSomeEvent();
}
}
}
Event Listener Implementation
public class SomeImplClass {
private InnerEventListener myEventListenerA = null;
private InnerEventListener myEventListenerB = null;
private String id = null;
public SomeImplClass(String id) {
this.id = id;
myEventListenerA = new InnerEventListener(id + "_A");
myEventListenerB = new InnerEventListener(id + "_B");
}
public void releaseListeners() {
myEventListenerA.unregisterListener();
myEventListenerB.unregisterListener();
}
private class InnerEventListener implements SomeEventListener {
private SomeEventManager someEventManager = null;
private String id = null;
public InnerEventListener(String id) {
someEventManager = SomeEventManager.getInstance();
this.id = id;
registerListener();
}
public void registerListener() {
someEventManager.addListener(this);
}
public void unregisterListener() {
someEventManager.removeListener(this);
}
public void handleSomeEvent() {
System.out.println("InnerEventListener->" + id);
}
}
}
The solution we use is to have the listener automatically unregister itself if it gets called and the thing it's updating has been collected.
It looks a bit like this:
private static class InnerEventListener implements SomeEventListener {
private final WeakReference<ThingToUpdate> thingRef;
public InnerEventListener(ThingToUpdate thing) {
thingRef = new WeakReference<>(thing);
}
#Override
public void handleSomeEvent(SomeEvent event) {
ThingToUpdate thing = thingRef.get();
if (thing != null) {
thing.updateSomehow();
} else {
((SomeEventedThing) event.getSource())
.removeSomeEventListener(this);
}
}
}
//...
SomeEventedThing eventedThing;
ThingToUpdate thingToUpdate;
//...
eventedThing.addListener(new InnerEventListener(thingToUpdate));
I wouldn't say it's a perfect solution because the listener sticks around until it gets an event, and it's still somewhat dependent on garbage collection. We've been trying to replace it with explicit removal where possible, usually on addNotify/removeNotify on GUI components.

Using POJOs as model layer in JavaFX application

I'm creating simple JavaFX application. I want my model layer to be completely independent from JavaFX - no StringProperty, IntegerProperty and etc. as fields. I want it to be POJO. Main reason to do so is that I want it to be Serializable.
I've created DataRepository - simple CRUD-like interface and some implementations of it, so I can at anytime change where I store my data - XML file, SQLite database or anything else. I also have to somehow connect my data storage with JavaFX (to display its content in TableView), so I decided to create my implementation of ObservableList which wraps my repository. My question is - is there any other way? ObservableList contains about 30 methods to implement and it looks like I'm doing something wrong.
My (simplified) model:
public class Movie implements Serializable {
private String title;
private String director;
public Movie() {
}
public Movie(String title, String director) {
this.title = title;
this.director = director;
}
// Getters and setters, equals etc...
}
MovieRepository:
public interface MovieRepository {
public void add(Movie movie);
public void remove(String title);
public void remove(int index);
public Movie get(String title);
public Movie get(int index);
public List<Movie> getAll();
}
Controller for my main view:
public class MainController {
#FXML
private TableView<Movie> movieTable;
#FXML
private TableColumn<Movie, String> movieTitleColumn;
#FXML
private Label titleLabel;
private MovieRepository movies = new DBMovieRepository(); //MovieRepository implementation which uses SQLite DB to store data
private MainApp app;
#FXML
private void initialize() {
movieTable.setItems(new ObservableMovies(movies));
// ObservableMovies is my implementation of ObservableList
// It basically wraps methods from MovieRepository
// and notifies listeners
showMovieDetails(null);
movieTitleColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getTitle()));
movieTable.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> showMovieDetails(newValue));
}
private void showMovieDetails(Movie movie) {
if(movie != null) {
titleLabel.setText(movie.getTitle());
} else {
titleLabel.setText("");
}
}
#FXML
private void handleNew() {
Movie movie = new Movie();
app.showNewMovieDialog(movie);
movieTable.getItems().add(movie);
}
public void setApp(MainApp app) {
this.app = app;
}
}
You have a couple of options here (maybe more), which are covered in other questions on this site. However, for convenience, I'll summarize them here too.
1. Use JavaFX Properties and make the class Serializable
You can do this with a custom serialized form. Make the JavaFX properties transient and implement readObject and writeObject to store the values they wrap:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Objects;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Movie implements Serializable {
private transient StringProperty title = new SimpleStringProperty();
private transient StringProperty director = new SimpleStringProperty();
public Movie() {
}
public Movie(String title, String director) {
setTitle(title);
setDirector(director);
}
#Override
public int hashCode() {
return Objects.hash(getDirector(), getTitle());
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Movie other = (Movie) obj;
return Objects.equals(getTitle(), other.getTitle())
&& Objects.equals(getDirector(), other.getDirector());
}
public final StringProperty titleProperty() {
return this.title;
}
public final String getTitle() {
return this.titleProperty().get();
}
public final void setTitle(final String title) {
this.titleProperty().set(title);
}
public final StringProperty directorProperty() {
return this.director;
}
public final String getDirector() {
return this.directorProperty().get();
}
public final void setDirector(final String director) {
this.directorProperty().set(director);
}
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
title = new SimpleStringProperty((String) s.readObject());
director = new SimpleStringProperty((String) s.readObject());
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeObject(getTitle());
s.writeObject(getDirector());
}
}
2. Use a POJO with "bound properties".
See JavaBean wrapping with JavaFX Properties for details. In brief:
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Movie {
private String title ;
private String director ;
private final PropertyChangeSupport propertySupport ;
public Movie(String title, String director) {
this.title = title ;
this.director = director ;
this.propertySupport = new PropertyChangeSupport(this);
}
public Movie() {
this("", "");
}
public String getTitle() {
return title ;
}
public String setTitle(String title) {
String oldTitle = this.title ;
this.title = title ;
propertySupport.firePropertyChange("title", oldTitle, title);
}
// similarly for director...
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(listener);
}
// hashCode and equals...
}
For wanting to wrap your repository as an observable list, instead wrap it with a repository implementation that uses an observable list:
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class ObservableMovieRepository implements MovieRepository {
private final MovieRepository repository ;
private final ObservableList<Movie> movieList;
public ObservableMovieRepository(MovieRepository repository) {
this.repository = repository ;
this.movieList = FXCollections.observableArrayList(repository.getAll());
}
#Override
public void add(Movie movie) {
repository.add(movie);
movieList.add(movie);
}
#Override
public void remove(String title) {
Movie movie = get(title);
repository.remove(title);
movieList.remove(title);
}
#Override
public void remove(int index) {
repository.remove(index);
movieList.remove(index);
}
#Override
public Movie get(String title) {
return repository.get(title);
}
#Override
public Movie get(int index) {
return movieList.get(index);
}
#Override
public ObservableList<Movie> getAll() {
return movieList ;
}
}
This uses the standard ObservableList implementation that copies an existing list on creation, and the implementation keeps that list in sync with the list in the wrapped repository. Now your UI code can do
ObservableMovieRepository movies = new ObservableMovieRepository(new DBMovieRepository());
// ...
movieTable.setItems(movies.getAll());
With the Movie class above, you would just do
movieTitleColumn.setCellValueFactory(cellData -> cellData.getValue().titleProperty());
If you use the POJO version you can do
movieTitleColumn.setCellValueFactory(cellData -> {
try {
return new JavaBeanStringPropertyBuilder()
.bean(cellData.getValue())
.name("title")
.build();
} catch (Exception e) { throw new RuntimeException(e); }
}
There seem to be multiple question in here, so I'm not really sure, if I understood you correctly, but I will try to split it up a bit.
I want my model layer to be completely independent from JavaFX - no
StringProperty, IntegerProperty and etc. as fields. I want it to be
POJO.
You could mark your properties as transient. Then you just need to wrap them around your values and it will be both JavaFX compliant and Serializable. You just have to propagate changes back to your backing attributes.
I also have to somehow connect my data storage with JavaFX (to display
its content in TableView), so I decided to create my implementation of
ObservableList which wraps my repository. My question is - is there
any other way?
Very limited information on this and I really don't know, why you would need to create your own implementation of ObservableList, but to keep it POJO, you could maintain plain java.util.Collections in your bean and provide transient ObservableLists, which you can create on creation by wrapping your java.util.Lists in your POJO. You can find those methods in the FXCollections utility class.
ObservableList contains about 30 methods to implement and it looks
like I'm doing something wrong.
If you really need to implement it, you can inherit from ObservableListBase.

Returning an element of a list based on an id

Does anyone know of any fancy guava function that will do the following for me.
Consider I have a list of object. Each object has an id. I have a list of 10 objects with ids from 1 to 10. I want to get at a particular object based on an id. What I usually do is
private MyObject findMyObjectById(List<MyObject> items, Integer id) {
for (MyObject item : items) {
if (id.equals(item.getId())) {
return item;
}
}
return null;
}
This is both verbose and repetitive as I cant type id (getId is not in any interface I have for various reasons)
Is there any fancy guava way to do this?
In this example I use FluentIterable's firstMatch.
Also in most cases avoid returning null, prefer Optional.
private final int id;
public MyObject(final int id) {
this.id = id;
}
public int getId() {
return this.id;
}
#Override
public String toString() {
return "MyObject [id=" + this.id + "]";
}
public static Optional<MyObject> findFirstByFilter(final List<MyObject> myObjects, final Predicate<MyObject> filter) {
return FluentIterable.from(myObjects)
.firstMatch(filter);
}
public static Optional<MyObject> findFirstById(final List<MyObject> myObjects, final Integer id) {
return findFirstByFilter(myObjects, new Predicate<MyObject>() {
#Override
public boolean apply(final MyObject myObject) {
return myObject.getId() == id;
}
});
}
public static void main(final String... args) {
final List<MyObject> myObjects = ImmutableList.of(new MyObject(1), new MyObject(2));
final Optional<MyObject> found = findFirstById(myObjects, 2);
//MyObject [id=2]
System.out.println(found.orNull());
final Optional<MyObject> notFound = findFirstById(myObjects, 5);
//null
System.out.println(notFound.orNull());
}
Java 8 version:
private final int id;
public MyObject(final int id) {
this.id = id;
}
public int getId() {
return this.id;
}
#Override
public String toString() {
return "MyObject [id=" + this.id + "]";
}
public static void main(final String... args) {
final List<MyObject> myObjects = ImmutableList.of(new MyObject(1), new MyObject(2));
final Optional<MyObject> found = myObjects.stream()
.filter(myObject -> myObject.getId() == 2)
.findAny();
// MyObject [id=2]
System.out.println(found.orElse(null));
final Optional<MyObject> notFound = myObjects.stream()
.filter(myObject -> myObject.getId() == 5)
.findAny();
// null
System.out.println(notFound.orElse(null));
}
I know you can't always modify your code to suite, but this is a pattern I saw on here somewhere (I can't find it now). We now use this a lot on our Entity objects, DTO's etc.
Create this interface:
public interface HasLongId {
public long getId();
}
Now in a LongIds class:
public static final Function<HasLongId, Long> GetIndex =
new Function<HasLongId, Long>() {
#Override
public Long apply(HasLongId hasId) {
return hasId.getId();
}
};
public static class NameMatcher implements Predicate<HasLongId> {
private final long id;
public NameMatcher(long id) {
this.id = id;
}
#Override public boolean apply(HasLongId hasId) {
return id == hasId.getId();
}
}
With that you can do:
public static final <V extends HasLongId> Iterator<Long> of(Iterator<V> items) {
return Iterators.transform(items, GetIndex);
}
public static final <V extends HasLongId> String join(Iterable<V> items) {
return Joiner.on(',').skipNulls().join(of(items));
}
public static final <V extends HasLongId> ImmutableMap<Long, V> mapOf(Iterable<V> items) {
return Maps.uniqueIndex(items, GetIndex);
}
public static final <V extends HasLongId> V find(Iterable<V> iterable, Long id) {
return Iterables.find(iterable, new NameMatcher(id));
}
public static final <V extends HasLongId> boolean contains(V[] array, Long id) {
return Iterators.contains(of(Iterators.forArray(array)), id);
}
and so on.
We also have this interface:
public interface HasName {
String getName();
}
Along with a class called Names which contains our utility methods.
Hope this helps a bit.
To answer your specific question, Iterables has a find method which takes a Predicate. I am not sure how "fancy" it is, you would have to implement a Predicate class which does the id comparison.
I will echo #JoachimIsaksson, though, this seems like you really would benefit from a Map<Integer,MyObject>.

Categories

Resources