How to change view of object in table cell? - JavaFx - java

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));
}
});

Related

What is the correct way to deal with fields in Kotlin?

How should I handle the migration from a Java class with fields to Kotlin properly?
A couple of reading into Kotlin's docs reveal that their classes can't have fields defined within them. Being the rebel that I am, actually trying to convert my existing Java code to its Kotlin counterpart (using Android Studio's Java to Kotlin converter feature) also marks "fields" with an unpleasantly blinding highlight.
This is my Java class:
public final class PaperDay implements Day {
private Date date;
private Weather weather;
PaperDay() {
// Obligatory empty ctor for Paper.
}
PaperDay(Date date) {
this.date = truncateTimeFromDate(date);
this.weather = Weather.SUNNY; // Default to SUNNY, 'cos sunny is good!
}
PaperDay(Date date, Weather weather) {
this.date = truncateTimeFromDate(date);
this.weather = weather;
}
private Date truncateTimeFromDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
...
..and this is what it looks like converted into a .kt:
How can I do this the Kotlin way?
I'm assuming you want something like this:
class PaperDay (private var date: Date,
private var weather: Weather = Weather.SUNNY) : Day {
init {
this.date = truncate(date)
}
private fun truncateTimeFromDate(date1: Date): Date {
return date1
}
}
You should try to use optional parameters (var weather: Weather = Weather.SUNNY) wherever you can, since it increases readability a lot.
To avoid the (somewhat ugly) init block you can also pass only one of the two properties as a constructor parameter (thanks to Jayson Minard), and calculate the other property in it's declaration by using a "normal" paramter:
class PaperDay (dateWithTime: Date,
private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
...
}
Note that this is also using val instead of var since immutability is usually the better option.
If you need to have the empty constructor as well, you can add this (although I don't think it's a good practice and it's an indicator for "bad"
design:
constructor() : this(Date())
Alternatively, adding a default value for all parameters in the constructor will implicitly create an empty constructor as well.
if you really want the nullability define your properties using ?. E.g.:
class PaperDay (private var date: Date?, private var weather: Weather? = Weather.SUNNY)
you can then also change the other constructor to constructor() : this(null)
Additionally, it's IMHO also a good idea to add the truncate... method as an extension function for the Date class instead of heaving it in this class:
fun Date.truncateTimeFromDate() {
Calendar calendar = Calendar.getInstance()
calendar.setTime(this)
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
...
}
Similar to #Lovis but avoiding the use of var which should be a "last resort":
class PaperDay (dateWithTime: Date = Date(), private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
...
}
}
In this version, the constructor has one parameter that is not a class property, and the other is a property. Later in the class body, the property is declared and set to the truncated date.
If you have a default value for each constructor parameter, Kotlin will automatically create a default constructor that uses those defaults. No need to add it separately.
If your framework must instantiate with default constructor and then set the values after the fact, you'll want to do something more like the following and go back to using var:
class PaperDay (dateWithTime: Date = Date(), private var weather: Weather = Weather.SUNNY): Day {
private var date: Date = truncateTimeFromDate(dateWithTime)
set(value) { field = truncateTimeFromDate(value) }
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
return dateWithTime
}
}
Now we have ensured we never have a invalid date being stored in the property by having a custom setter.
If you want interoperability for all variations of the constructor available from Java, you can use the #JvmOverloads annotation on the constructor to generate other permutations of using default parameter values.
And as #Lovis points out, move the truncateTimeFromDate to an extension function on the Date class. It can be local to the file, to the module, to the class, and in all those cases it will read better.

javaFX show calendar value in tableview

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()));
}
}
});

Java system time

I have this code copied from one of questions from SO:
public static String getCurrentTimeStamp() {
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date();
String strDate = sdfDate.format(now);
return strDate;
}
I want to get only the system time and NOT the date. Then I must change second line of code to:
SimpleDateFormat sdfDate = new SimpleDateFormat(" HH:mm:ss") ;
Then, DATE() must get the current time. Clear upto this point but I can't understand the format() function used.
I mean cant we simply output variable now instead of strdate?
Is it just because that the return type of function getCurrentTimeStamp() is String?
Please clarify and if there is any other simpler and one line code for getting system time alone, do share.
I mean cant we simply output variable now instead of strdate.
Well you could return now.toString() - but that will use the format that Date.toString() happens to choose, whereas you want a specific format. The point of the SimpleDateFormat object in this case is to convert a Date (which is a point in time, without reference to any particular calendar or time zone) into a String, applying an appropriate time zone, calendar system, and text format (in your case HH:mm:ss).
You can still simplify your method somewhat though, by removing the local variables (which are each only used once):
public static String getCurrentTimeStamp() {
return new SimpleDateFormat("HH:mm:ss").format(new Date());
}
Or maybe you'd find it more readable to keep the variable for the date format, but not the date and the return value:
public static String getCurrentTimeStamp() {
DateFormat format = new SimpleDateFormat("HH:mm:ss");
return format.format(new Date());
}
Personally I'd recommend using Joda Time instead, mind you - it's a much nicer date/time API, and its formatted are thread-safe so you could easily keep a reference to a single formatting object.
public static String getCurrentTimeStampwithTimeOnly() {
return new SimpleDateFormat("HH:mm:ss").format(new Date());
}
Helps you to do this.
you can call this line any time
Date now = new Date();
The now variable will contain the current timestamp
The format function just generates a String from this timestamp
also take a look at the Calendar class ( Calendar.getInstance())

GWT Editor use IsEditor<LeafValueEditor<Date>> to populate Long field

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);
}
}

using the date type in java

I am trying to get two dates from a SQL query, and compare them. So to compare them, I believe I will need to use the "Date" type. Here is what I am trying, I know I am getting the date from the resultSet incorrectly, but I am not sure how to do it.
Date validDate = new Date(0);
Date currentDate = new Date(0);
// query
if (result.next()) {
validDate = (result.getObject("validDate")!=null)?result.getObject("validDate").toDate():"";
currentDate = (result.getObject("currentDate")!=null)?result.getObject("currentDate").toDate():"";
}
if (currentDate > validDate) {
//do something
}
So again, this was my attempt, but I cant seem to get it to run. Thanks in advance.
EDIT: the query has TO_CHAR(column, 'MM-DD-YYYY') on the two dates that I am getting.
EDIT: Now you've mentioned that your query converts the date to a string, stop doing that. You'll end up reparsing it on the calling side - so why perform two conversions pointlessly? Keep string conversions to the absolute minimum - stay in the most appropriate data type wherever possible.
Original answer
You haven't shown what result is, but you probably want something like ResultSet.getDate() to fetch the date values.
Note that your comparison code won't work either because there's no > for Date - you'd need something like:
if (currentDate.after(validDate))
Or fetch the underlying number of millis:
if (currentDate.getTime() > validDate.getTime())
Additionally:
You can't assign "" to a Date variable - a string isn't a Date.
You can just call ResultSet.getDate() and check whether the returned value is null, rather than calling getObject first and then getDate()
Try currentDate.after(validDate)
To compdare dates I always use the before and after methodes of Date.
Some nasty things can happen when accessing dates via the getObject method. You should try to use the rs.getTimestamp (with timeinfo) or the rs.getDate (without timeinfo) methods.
Also, because of the rather complex hierarchy of Date-objects you should compare Dates only using the date1.compareTo(date2) > 0 method.
if your result object is ResultSet, then
Date validDate = result.getTimestamp("validDate");
Date currentDate= result.getTimestamp("currentDate");
// you can add null checks here too....
// you can also use if (currentDate.getTime() > validDate.getTime()){}
if (currentDate.before(validDate)) {
//some code inhere...
}
There are at least three things wrong with your code:
"" is a String literal, so you cannot use it int your ternary expressions to be assigned to a variable of type Date - use null instead so you don't need a ternary
ResultSet.getObject() returns an Object, which does not have a toDate() method. Instead, simply use ResultSet.getDate()
You cannot compare Date instances using a > operator. You have to use the before() and after() methods of the Date class
Taking all this together, the following code might work:
Date validDate = new Date(0);
Date currentDate = new Date(0);
if (result.next()) {
validDate = result.getDate("validDate");
currentDate = result.getDate("currentDate");
}
if (currentDate.after(validDate)) {
//do something
}
The if clause may have to include some extra logic to deal with null values though. It's better to do that than to leave that to implicit conversions, too.

Categories