mgarin / weblaf

WebLaF is a fully open-source Look & Feel and component library written in pure Java for cross-platform desktop Swing applications.
http://weblookandfeel.com
GNU General Public License v3.0
1.13k stars 234 forks source link

date/time not getting updated in WebDateField #579

Closed mokun closed 4 years ago

mokun commented 4 years ago

I just found out an issue with WebDataField.

See also https://github.com/mgarin/weblaf/issues/257

I can set the date/time to a value INITIALLY as follows :

// Global data member
Date date = new Date(earthClock.getInstant().toEpochMilli());
// Within a method
WebDateField dateField = new WebDateField (date);
DateFormat d = new SimpleDateFormat ("yyyy-MMM-dd  HH:mm a '['z']'", LanguageManager.getLocale ());
dateField.setDateFormat(d);

However, in my app's game loop, I need to constantly update the date/timestamp.

So if I do the following once per frame, it won't work :

date = new Date(earthClock.getInstant().toEpochMilli());
dateField.setDate(date)

OR:

date.setTime(earthClock.getInstant().toEpochMilli());
// dateField.setDate(date);

The only way it works is keeping create a brand new Date each time as follows:

dateField.setDate(new Date(earthClock.getInstant().toEpochMilli()));

mgarin commented 4 years ago

Thanks for the information! I'll check that tomorrow and add a fix.

mgarin commented 4 years ago

So if I do the following once per frame, it won't work :

date = new Date(earthClock.getInstant().toEpochMilli());
dateField.setDate(date)

This most certainly works for me, can you provide a small example where it doesn't for you? Which exact WebLaF version it doesn't work on?

OR:

date.setTime(earthClock.getInstant().toEpochMilli());
// dateField.setDate(date);

This is actually a bad idea, WebDateField cannot possibly know when you change time within the Date object because unfortunately there are no ways to listen to it's changes, so WebDateField obviously won't update displayed date like that.

I personally recommend to never ever reuse Date object and always create a new one, because even if you will change it's time and provide it again into WebDateField - it won't update because of how parameters comparison works. It's "cheap" to create a new one anyway, so there is no reason not to.

mokun commented 4 years ago

I'm on v1.2.10.

I personally recommend to never ever reuse Date object and always create a new one, because even if you will change it's time and provide it again into WebDateField it won't update because of how parameters comparison works. It's "cheap" to create a new one anyway, so there is no reason not to.

Ok I surely hope there's a way to listen in the changes in the timestamp.

One big problem I found in my app is that if I click on the calendar button on the right of the textfield, it won't open the calendar. OR should I say as soon as it's being opened, since a new Date object is being provided to increment/update the time, the calendar will collapse.

So updating the Date object frequently will totally defeat the purpose of having the WeDateField in that users can see the visual calendar :(

Is there a workaround to keep the calendar object in the open state, while the Date is being updated ?

EDIT: May be there is a way to temporarily put ON-HOLD the firing of the UI refresh on the calendar component until the mouse cursor exit the calendar or when the calendar is no longer in the popped-out state ?!

mgarin commented 4 years ago

Ok I surely hope there's a way to listen in the changes in the timestamp.

Not sure what you meant by that.

If you set a new Date instance into the field - it will be recognized, but if you simply change time in Date that was set into it before OR set the same instance of Date you set into the field before - it won't be recognized.

Unfortunately nothing can be done about the first case because Date object doesn't notify anyone about it's time change, you can see that in setTime ( long ) method:

    /**
     * Sets this <code>Date</code> object to represent a point in time that is 
     * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT. 
     *
     * @param   time   the number of milliseconds.
     */
    public void setTime(long time) {
    fastTime = time;
    cdate = null;
    }

For the second case I've added a small fix that will simply use a new Date instance and return copy of selected Date instance to avoid it being modified from outside.

mgarin commented 4 years ago

@mokun

One big problem I found in my app is that if I click on the calendar button on the right of the textfield, it won't open the calendar. OR should I say as soon as it's being opened, since a new Date object is being provided to increment/update the time, the calendar will collapse.

Is there a workaround to keep the calendar object in the open state, while the Date is being updated ?

Could you provide a small code example of this use-case?

mgarin commented 4 years ago

Date field popup will not close anymore when date or date format is changed while it's open. Calendar will properly update to newly provided date as well.

Here is the example I used for testing this problem:

public final class DateCalendarPopupTest
{
    public static void main ( final String[] args )
    {
        SwingTest.run ( new Runnable ()
        {
            @Override
            public void run ()
            {
                final WebDateField dateField = new WebDateField ( new Date () );

                TestFrame.show ( dateField );

                WebTimer.repeat ( 1000, new ActionListener ()
                {
                    @Override
                    public void actionPerformed ( final ActionEvent e )
                    {
                        dateField.setDate ( new Date ( dateField.getDate ().getTime () + 24 * 60 * 60 * 1000 ) );
                    }
                } );
            }
        } );
    }
}