I have the following problem.
I'm making a assignment for school, we need to show a gregoriancalendar value in a tableview.
this is my code for the table
TableColumn geboortedatum = new TableColumn("Geboortedatum");
geboortedatum.setCellValueFactory(new PropertyValueFactory<Persoon, SimpleDateFormat>("gebDat"));
When I actually run this I get the following value in my tableview no matter what.
java.util.GregorianCalendar[time=-23574157200000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startyear=0,startMode=2,startMonth=2,startDay=-1,startTime=360000
and it goes on like that.
anyone who has a simple solution for me? I'm probably missing something really easy here.
First, it looks you have the wrong type for the PropertyValueFactory. You get away with this because you are using a raw TableColumn, but your code will be easier to understand if you properly type the column. From the output, I can see that your Persoon.getGebDat() method returns a Calendar object. So you should have
TableColumn<Persoon, Calendar> geboortedatum = new TableColumn<>("Geboortedatum");
geboortedatum.setCellValueFactory(new PropertyValueFactory<Persoon, Calendar>("gebDat"));
The default behavior of a TableCell is to call the toString method of the item it is displaying. The text you are seeing is the result of calling toString on your Calendar object.
To change the way the data is displayed, you need to specify a cell factory on the TableColumn that creates a TableCell that knows how to format the Calendar as you want it.
So you'll do something like
final DateFormat dateFormat = DateFormat.getDateInstance() ; // or whatever format object you need...
geboortedatum.setCellFactory(col -> new TableCell<Persoon, Calendar>() {
#Override
public void updateItem(Calendar item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
setText(null);
} else {
setText(dateFormat.format(item.getTime()));
}
}
});
Related
I'm new to JavaFX and was wondering if the Bindings API allowed an easier way to achieve the following. Consider a model that contains a database that may be null (because the database loads asynchronously) and a view that displays a label status reflecting the state of the database. If it is null it should say something like "Loading..." and if it isn't it should display how many items are in the database. It also would be great if the status could reflect the size of the database as it grows or shrinks.
So far, I understand that I could bind an integer property (size of the database) to the text property of the label by using a converter. This is fine, but I want the label to display more than the number. A localized string like "Loaded {0} items" precisely. And let's not forget that the database may still be null.
This is the solution I have in place
#Override
public void initialize(URL url, ResourceBundle bundle) {
// Initialize label with default value
status();
model.databaseProperty().addListener((obs, old, neu) -> {
// Update label when database is no longer null
status();
// Update label when size of database changes
neu.sizeProperty().addListener(x -> status());
});
}
public void status() {
if (model.database() == null) {
status.setText(bundle.getString("status.loading"));
} else {
String text = bundle.getString("status.ready");
int size = model.database().size();
text = new MessageFormat(text).format(size);
status.setText(text);
}
}
It works, but is there a way to do it with a chain of bindings, or at least part of it? I've seen how powerful (and lenghty) boolean bindings can be but I'm not sure something as flexible is possible with string bindings.
You can use Bindings.when, which is essentially a dynamic if/then binding:*
status.textProperty().bind(
Bindings.when(model.databaseProperty().isNull())
.then(bundle.getString("status.loading"))
.otherwise(
Bindings.selectInteger(model.databaseProperty(), "size").asString(
bundle.getString("status.ready")))
);
However, the above assumes bundle.getString("status.ready") returns a java.util.Formatter string, not a MessageFormat string. In other words, it would need to be "Loaded %,d items" rather than "Loaded {0,number,integer} items".
Bindings doesn’t have built-in support for MessageFormat, but if you really want to stick with MessageFormat (which is a legitimate requirement, as there are things MessageFormat can do which Formatter cannot), you can create a custom binding with Bindings.createStringBinding:
MessageFormat statusFormat = new MessageFormat(bundle.getString("status.ready"));
status.textProperty().bind(
Bindings.when(model.databaseProperty().isNull())
.then(bundle.getString("status.loading"))
.otherwise(
Bindings.createStringBinding(
() -> statusFormat.format(new Object[] { model.getDatabase().getSize() }),
model.databaseProperty(),
Bindings.selectInteger(model.databaseProperty(), "size")))
);
* Actually, it’s more like the ternary ?…: operator.
I am trying to do the following:
tableColumns[0].setCellValueFactory(
new PropertyValueFactory<DiaryEntry,String>("username")
);
tableColumns[1].setCellValueFactory(
new PropertyValueFactory<DiaryEntry,Project>("project")
);
So the first one works perfectly fine. It uses the getUsername() Method in my class "DiaryEntry" in order to the Display the String. The second one is using the Method getProject() and tries to add the Project to my table. When doing that I end up with something like "2xProject2353asxk". This makes perfectly sense, since it can not simply display the Project object in the table.
In my Class Project I have a getter "getName()". So my Question here is: Is there any way I can change my second Statement, so that the table will enter the Project's name? I read a couple of threads about the setCellValueFactory() Method, but I still can't figure a solution out.
Use a cellFactory in addition to the cellValueFactory
tableColumns[1].setCellValueFactory(
new PropertyValueFactory<DiaryEntry,Project>("project")
);
tableColumns[1].setCellFactory(col -> new TableCell<DiaryEntry, Project>() {
#Override
protected void updateItem(Project project, boolean empty) {
super.updateItem(project, empty);
if (empty) {
setText(null);
} else {
setText(project.getName());
}
}
});
The cellValueFactory tells the column what value to display in its cells; the cellFactory tells it how to display the value.
I have a column of LocalDateTime in my TableView:
column_AddDate = new TableColumn<MyTableItem, LocalDateTime>(TITLE_ADD_DATE)
But result - 2016-02-05T12:26:20.506 - is not so pretty as for me. I want to store and sort table data using rules of LocalDateTime class, but show it with custom format. For example:
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
formattedDateTime = dateTime.format(formatter); // "2016-02-05 12:26"
First, that I've tryed, is to write custom class DateTimeForTable extends LocalDateTime and override toString() method, but LocalDateTime is final.
So, I think, solution is in using setCellValueFactory() method and similar, but I'm not skilled in this.
Please tell me, how to realize this feature.
To change the way the data is presented, rather than the data itself, you should use a cellFactory. (I assume you already have a cellValueFactory installed, else you would not see any data at all. Note the cellFactory is in addition to the cellValueFactory, it does not replace it.)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
column_AddDate.setCellFactory(tc -> new TableCell<MyTableItem, LocalDateTime>() {
#Override
protected void updateItem(LocalDateTime item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : formatter.format(item));
}
});
I have a class called "Product", with a double attribute "price". I'm showing it on a table column inside a table view, but i wanted to show the price formatted -- "US$ 20.00" instead of just "20.00".
Here's my code for populating the table view:
priceProductColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
I tried everything: convert the returned value to a string, using the method toString that priceProperty has, etc, but not seems to work.
Do i need to bind an event of something like that?
Use the cellValueFactory as you have it to determine the data that is displayed. The cell value factory is basically a function that takes a CellDataFeatures object and returns an ObservableValue wrapping up the value to be displayed in the table cell. You usually want to call getValue() on the CellDataFeatures object to get the value for the row, and then retrieve a property from it, exactly as you do in your posted code.
Use a cellFactory to determine how to display those data. The cellFactory is a function that takes a TableColumn (which you usually don't need) and returns a TableCell object. Typically you return a subclass of TableCell that override the updateItem() method to set the text (and sometimes the graphic) for the cell, based on the new value it is displaying. In your case you get the price as a Number, and just need to format it as you require and pass the formatted value to the cell's setText(...) method.
It's worth reading the relevant Javadocs: TableColumn.cellFactoryProperty(), and also Cell for a general discussion of cells and cell factories.
priceProductColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
priceProductColumn.setCellFactory(col ->
new TableCell<Product, Number>() {
#Override
public void updateItem(Number price, boolean empty) {
super.updateItem(price, empty);
if (empty) {
setText(null);
} else {
setText(String.format("US$%.2f", price.doubleValue()));
}
}
});
(I'm assuming priceProductColumn is a TableColumn<Product, Number> and Product.priceProperty() returns a DoubleProperty.)
If you have not, read this together with #James_D post.
https://docs.oracle.com/javafx/2/ui_controls/table-view.htm
I just got the hang of using the Editor framework and am porting over all my forms to use it. I'm running into some trouble on my Event form. I have 5 different time fields - for each field I use a DateBox to allow the user to select the time.
In my old Activity i converted the values of these fields to Long times, populated my proxy object and persisted it.
I want to do the same thing using the Editor framework. Is there anyway I can use an Editor with a DateBox to populate a Long field in my domain object. I'm sure there's got to be a way to do this I'm just having trouble figuring it out.
If this is not the case and I just can't do this for now, does anybody know a good solution for how to do this?
You have to wrap the DateBox in an Editor<Long>. Something like:
#Editor.Ignore
#UiField
DateBox dateField;
LeafValueEditor<Long> longField = new LeafValueEditor<Long>() {
#Override
public Long getValue() {
Date date = dateField.getValue();
return date == null ? null : date.getTime();
}
#Override
public void setValue(Long value) {
Date date = value == null ? null : new Date(value.longValue());
dateField.setValue(date);
}
}