cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

JavaFX Binding with WorkItem

SOLVED
Highlighted
Regular Member

JavaFX Binding with WorkItem

I am working on a tool using the Integrity Java API. I am using JavaFX for the UI. I have a TableView and right now, to bind an ObservableList, I am converting a WorkItem to a different object type that I have cleverly named WorkItem2. What I am doing is in the below code snippet (the real class uses more fields). This allows me to use an ObservableList<WorkItem2> and then use normal data binding with JavaFX.

 

My question is, is there a way to do data binding with WorkItems directly? I would like to avoid having to create properties for every field if possible.

 

public class WorkItem2 {
    private SimpleStringProperty id;
    private SimpleStringProperty project;
    private SimpleStringProperty summary;
public WorkItem2(WorkItem source) { id = new SimpleStringProperty(source.getId()); Iterator fields = source.getFields(); while (fields.hasNext()) { Field field = (Field) fields.next(); String name = field.getName(); switch (name) { case "Project": project = new SimpleStringProperty(field.getValueAsString()); break; case "Summary": summary = new SimpleStringProperty(field.getValueAsString()); break; default: break; } } } public String getID() { return id.get(); } public void setID(String s) { id.set(s); } public String getProject() { return project.get(); } public void setProject(String s) { project.set(s); } public String getSummary() { return summary.get(); } public void setSummary(String s) { summary.set(s); } }

 

1 ACCEPTED SOLUTION

Accepted Solutions

Re: JavaFX Binding with WorkItem

Here's what I came up with. This works with displaying WorkItem field values in a TableView in JavaFX.

 

First, I had to make a new Cell Value Factory to work with items.

public class WorkItemValueFactory<S extends WorkItem, T> implements
        Callback<CellDataFeatures<S, T>, ObservableValue<T>> {

    private final String fieldName;

    public WorkItemValueFactory(@NamedArg("fieldname") String fieldName) {
        this.fieldName = fieldName;
    }

    @Override
    public ObservableValue<T> call(CellDataFeatures<S, T> param) {
        WorkItem item = param.getValue();

        if (!hasField(item)) return null;

        Field field = item.getField(fieldName);

        return new ReadOnlyObjectWrapper<T>((T)getValueToUse(field));
    }

    private static Object getValueToUse(Field field) {
        Object value = field.getValue();

        if (value instanceof String ||
                value instanceof Integer ||
                value instanceof Boolean) {
            return value;
        } else {
            return field.getValueAsString();
        }
    }

    private boolean hasField(WorkItem item) {
        if (fieldName == null || item == null || fieldName.isEmpty())
            return false;
        else
            return item.contains(fieldName);
    }
}

 

Then, the items need to be retrieved and added to an observable list:

// Create an observable list to add the WorkItems to.
ObservableList<WorkItem> workItemList = FXCollections.observableArrayList();

// Set this list to the table view.
tableView.setItems(workItemList);

// Add the work items that were retrieved from ILM to the observable list.
for (WorkItem i : items)
            workItemList.add(i);

 

 

The FXML for this looks like:

<TableView fx:id="tableView">
	<columns>
		<TableColumn text="ID">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="ID" />
			</cellValueFactory>
		</TableColumn>
		<TableColumn text="State">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="State" />
			</cellValueFactory>
		</TableColumn>
		<TableColumn text="Type">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="Type" />
			</cellValueFactory>
		</TableColumn>
		<TableColumn text="Summary">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="Summary" />
			</cellValueFactory>
		</TableColumn>
	</columns>
</TableView>

View solution in original post

3 REPLIES 3

Re: JavaFX Binding with WorkItem

Hi,

as far as I know there one general problem.

In JavaFX you need the "values" to be reprensented by "Properties"; this includes a properly namen getter an setter function for each property.

see http://what-when-how.com/javafx-2/understanding-key-interfaces-and-concepts-properties-and-bindings-...

 

The fields in a Workitem are in most cases String or int or List.

Maybe you can write a factory class to generate the properties for a given WorkItem...

 

I personally use dedicated classes and properties to represent Workitems in my Apps. For memory efficiency I read the Workitems eg. by query, iterate the results, create objects incl. properties as needed and then release all workitem related memory. For Documents up to 5000 nodes this work quite well.

HTH

Matthias

Re: JavaFX Binding with WorkItem

That sounds basically like what I'm doing as well. In my C# app, I create separate classes for item types. For my Java app, I'm using the WorkItem2 thing I referenced. I'm messing with a SimpleMapProperty<String, Object> now to see if I can convert fields that way. I'll update this if I figure out anything interesting.

Re: JavaFX Binding with WorkItem

Here's what I came up with. This works with displaying WorkItem field values in a TableView in JavaFX.

 

First, I had to make a new Cell Value Factory to work with items.

public class WorkItemValueFactory<S extends WorkItem, T> implements
        Callback<CellDataFeatures<S, T>, ObservableValue<T>> {

    private final String fieldName;

    public WorkItemValueFactory(@NamedArg("fieldname") String fieldName) {
        this.fieldName = fieldName;
    }

    @Override
    public ObservableValue<T> call(CellDataFeatures<S, T> param) {
        WorkItem item = param.getValue();

        if (!hasField(item)) return null;

        Field field = item.getField(fieldName);

        return new ReadOnlyObjectWrapper<T>((T)getValueToUse(field));
    }

    private static Object getValueToUse(Field field) {
        Object value = field.getValue();

        if (value instanceof String ||
                value instanceof Integer ||
                value instanceof Boolean) {
            return value;
        } else {
            return field.getValueAsString();
        }
    }

    private boolean hasField(WorkItem item) {
        if (fieldName == null || item == null || fieldName.isEmpty())
            return false;
        else
            return item.contains(fieldName);
    }
}

 

Then, the items need to be retrieved and added to an observable list:

// Create an observable list to add the WorkItems to.
ObservableList<WorkItem> workItemList = FXCollections.observableArrayList();

// Set this list to the table view.
tableView.setItems(workItemList);

// Add the work items that were retrieved from ILM to the observable list.
for (WorkItem i : items)
            workItemList.add(i);

 

 

The FXML for this looks like:

<TableView fx:id="tableView">
	<columns>
		<TableColumn text="ID">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="ID" />
			</cellValueFactory>
		</TableColumn>
		<TableColumn text="State">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="State" />
			</cellValueFactory>
		</TableColumn>
		<TableColumn text="Type">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="Type" />
			</cellValueFactory>
		</TableColumn>
		<TableColumn text="Summary">
			<cellValueFactory>
				<WorkItemValueFactory fieldname="Summary" />
			</cellValueFactory>
		</TableColumn>
	</columns>
</TableView>

View solution in original post