This discussion is archived
1 2 Previous Next 23 Replies Latest reply: Apr 3, 2013 9:50 PM by KonradZuse Go to original post RSS
  • 15. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    KonradZuse Explorer
    Currently Being Moderated
    When I do that my millisecond amount does change, so that is interesting, even though it happens when I do
    Timeline countdown = new Timeline(
                    
                     new KeyFrame(javafx.util.Duration.ZERO,
                    (event)-> labelC.setText(clock.toString())),
              
                    new KeyFrame(javafx.util.Duration.ONE,
                    (event) -> clock = LocalTime.now()));
    
              countdown.setCycleCount(Timeline.INDEFINITE);
              countdown.play();  
        }
    I had it set to update the LocalTime.now but I figured adding a second would be better... guess not? Why is that?


    Also I'm a little confused how the "DataFormatter" works.
     DateTimeFormatter d = DateTimeFormatter.ofPattern("h");
    I tried using the "ofPattern" method and entering "h" and then doing
    clock = LocalTime.parse("10", d); 
    but I get an error...
     Caused by: java.time.format.DateTimeParseException: Text '10' could not be parsed: Unable to obtain LocalTime from TemporalAccessor: class java.time.format.DateTimeBuilder
    public static DateTimeFormatter ofPattern(String pattern)
    Creates a formatter using the specified pattern.
    This method will create a formatter based on a simple pattern of letters and symbols. For example, d MMM yyyy will format 2011-12-03 as '3 Dec 2011'.
    
    The returned formatter will use the default locale, but this can be changed using withLocale(Locale).
    
    All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The following pattern letters are defined:
    
      Symbol  Meaning                     Presentation      Examples
      ------  -------                     ------------      -------
       G       era                         text              A; AD; Anno Domini
       y       year                        year              2004; 04
       D       day-of-year                 number            189
       M       month-of-year               number/text       7; 07; Jul; July; J
       d       day-of-month                number            10
    
       Q       quarter-of-year             number/text       3; 03; Q3
       Y       week-based-year             year              1996; 96
       w       week-of-year                number            27
       W       week-of-month               number            27
       e       localized day-of-week       number            2; Tue; Tuesday; T
       E       day-of-week                 number/text       2; Tue; Tuesday; T
       F       week-of-month               number            3
    
       a       am-pm-of-day                text              PM
       h       clock-hour-of-am-pm (1-12)  number            12
       K       hour-of-am-pm (0-11)        number            0
       k       clock-hour-of-am-pm (1-24)  number            0
    
       H       hour-of-day (0-23)          number            0
       m       minute-of-hour              number            30
       s       second-of-minute            number            55
       S       fraction-of-second          fraction          978
       A       milli-of-day                number            1234
       n       nano-of-second              number            987654321
       N       nano-of-day                 number            1234000000
    
       V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
       z       time-zone name              zone-name         Pacific Standard Time; PST
       X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
       x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
       Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
    
       p       pad next                    pad modifier      1
    
       '       escape for text             delimiter
       ''      single quote                literal           '
       [       optional section start
       ]       optional section end
       {}      reserved for future use
    I'm not too sure exactly how to set it up.

    I tried doing
    ofPattern("hh"); and then tried their example above ofPattern("d MMM yyyy");
    
    
    and then used LocalDate date = LocalDate.parse("2011-12-03", d);  like they did, and nothing
    I would do hour 1-12, minute, second, and then AM/PM, but so far it's not looking too easy. We also have to specify the text for each?????


    Thanks,


    ~KZ


    Also thanks for the immutable post above, I agree that unchangable objects is a good thing in certain respects.




    I
    Edited by: KonradZuse on Mar 29, 2013 6:33 PM

    Edited by: KonradZuse on Mar 29, 2013 6:37 PM

    Edited by: KonradZuse on Mar 29, 2013 6:57 PM

    Edited by: KonradZuse on Mar 29, 2013 6:57 PM

    Edited by: KonradZuse on Mar 29, 2013 7:13 PM

    Edited by: KonradZuse on Mar 29, 2013 7:19 PM

    Edited by: KonradZuse on Mar 29, 2013 7:21 PM
  • 16. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    James_D Guru
    Currently Being Moderated
    For the formatter, something like:
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm:ss a");
    ...
    clockLabel.setText(formatter.format(clock));
    See [url http://download.java.net/jdk8/docs/api/java/time/format/DateTimeFormatter.html#ofPattern(java.lang.String)]DateTimeFormatter.ofPattern for the pattern syntax.

    I think DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM) will give you the same format, if you don't want to mess with the pattern syntax.

    Set the clock (LocalTime object) exactly as before; don't try to parse it from anything.

    If you add one second to the clock each time, you add exactly one second, even if the iteration takes very slightly longer. Eventually you'll be way behind. If you update it to the system clock each time, it will always be (at least very close to) the system time, no matter how slowly the iteration runs.
  • 17. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    KonradZuse Explorer
    Currently Being Moderated
    ended up trying
                        String s = clock.toString(d);
                       LocalTime t = LocalTime.parse(s, d);
    like in the doc, but it doesn't work; however doing
     clock.toString(d); 
    does in fact work and return the hour specified by "h."

    As you said above I shouldn't parse it seems, not too sure why it says to in the docs. The format I first saw it wanted a "TemporalAccessor" but then I checked and realized LocalTime implements it, so thanks for that, I didn't think about that before, it seems much easier to format it using the formatter, not the other way around.
  • 18. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    KonradZuse Explorer
    Currently Being Moderated
    James_D wrote:
    I think you can still use the techniques in the code sample jsmith showed.

    Also, if you're using JDK8, there's a nice new time API that is much better than java.util.Calendar.

    For example:
    import java.time.Instant;
    import java.time.Duration; 
    
    import javafx.animation.KeyFrame;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.binding.Bindings;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    
    public class Timer extends Application {
    
         private static final Duration COUNTDOWN_LENGTH = Duration.ofSeconds(60) ;
         
         @Override
         public void start(Stage primaryStage) {
              final Label label = new Label("Press button to start");
              final Button button = new Button("Start");
              final IntegerProperty secondsRemaining = new SimpleIntegerProperty();
              label.textProperty().bind(
                        Bindings.when(secondsRemaining.greaterThan(0))
                        .then(Bindings.format("Seconds remaining: %d", secondsRemaining))
                        .otherwise("Press button to start"));
              button.setOnAction(event -> startTimer(secondsRemaining) );
              button.disableProperty().bind(secondsRemaining.greaterThan(0));
              VBox root = new VBox(5);
              root.getChildren().addAll(label, button);
              Scene scene = new Scene(root, 200, 50);
              primaryStage.setScene(scene);
              primaryStage.show();
         }
         
         private void startTimer(final IntegerProperty secondsRemaining) {
              final Instant finishTime = Instant.now().plus(COUNTDOWN_LENGTH);
              Timeline countdown = new Timeline(
                   new KeyFrame(javafx.util.Duration.ZERO, 
                             (event) -> secondsRemaining.set((int) Duration.between(Instant.now(), finishTime).getSeconds())
                    ),
                   new KeyFrame(javafx.util.Duration.seconds(1))
              );
              countdown.setCycleCount((int)COUNTDOWN_LENGTH.getSeconds());
              countdown.play();
         }
    
         public static void main(String[] args) {
              launch(args);
         }
    }
    I also was looking at this code earlier and wanted to know why you used what you did?

    IntegerProperty? Bindings? Instance AND Duration?

    I tried this on my own with duration and everything worked except trying to set my Label's text to the duration's second count since .toString() doesn't return time.

    I was thinking that maybe I should also use the bindings, but do I have to use IntegerProperty?

    It seems like I have to use .when .then and .otherwise together. (is there a tutorial I should look at)? The binding also seems to work in real time, so no matter what is being changed, the label is updated, so couldn't we just use an integer value like int sec = 60; and just do sec--l and setText(sec)? Which is what I do now, except I setText each time.

    In curious what the point of using duration/instance would be? I'm also interested in why you used the "Between" method?
  • 19. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    James_D Guru
    Currently Being Moderated
    >

    I also was looking at this code earlier and wanted to know why you used what you did?

    IntegerProperty? Bindings?
    Any time you have multiple parts of the UI whose appearance depend on the same value, it makes sense to put that value in a property and use bindings to keep the UI in sync.

    Here the Label (its text) and the Button (its enabled/disabled state) both depend on how many seconds remain in the countdown.
    Instance AND Duration?
    An Instance represents a moment in time (e.g. 9:02:37.537 am on March 30 2013). A Duration represents a quantity of time (e.g. 10 seconds).

    The Duration.between(Instant, Instant) method gives the Duration between two Instants. So Duration.between(Instant.now(), finishTime) is the amount of time left in the countdown.

    >
    I tried this on my own with duration and everything worked except trying to set my Label's text to the duration's second count since .toString() doesn't return time.

    I was thinking that maybe I should also use the bindings, but do I have to use IntegerProperty?
    Whatever works for you...
    >
    It seems like I have to use .when .then and .otherwise together. (is there a tutorial I should look at)? The binding also seems to work in real time, so no matter what is being changed, the label is updated, so couldn't we just use an integer value like int sec = 60; and just do sec--l and setText(sec)? Which is what I do now, except I setText each time.
    You could use that approach, but then your countdown timer would have to know about your label. If you wrap the important data as a property you could easily make an independent class for the countdown timer which could be reused in your application any time you needed it.

    >
    In curious what the point of using duration/instance would be? I'm also interested in why you used the "Between" method?
  • 20. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    KonradZuse Explorer
    Currently Being Moderated
    Yeah it seems I still have a bit to learn about the full capabilities of JavaFX.

    I noticed how great the bindings were, except do I need to use .when, .then, AND .otherwise? If I only wanted to bind it base on 1 value or even .when, .then? The properties themselves are what we are binding?

    Also I knew what the difference was, but thanks for the recap, I was curious why you used BOTH of them, instead of just duration for example?


    I think it's better I learn about this stuff now, because as you said it seems to be important, and help with the WORA and clean code :).
  • 21. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    James_D Guru
    Currently Being Moderated
    KonradZuse wrote:
    Yeah it seems I still have a bit to learn about the full capabilities of JavaFX.

    I noticed how great the bindings were, except do I need to use .when, .then, AND .otherwise? If I only wanted to bind it base on 1 value or even .when, .then? The properties themselves are what we are binding?
    Bindings.when().then().otherwise() lets you bind to a conditional expression. You only need that when the value you're computing depends on a condition. Check the API docs for the Bindings class.
    >
    Also I knew what the difference was, but thanks for the recap, I was curious why you used BOTH of them, instead of just duration for example?
    Well, that's all there is. I use Duration when I need to represent a quantity of time (the amount of time left in the countdown, for example) and Instant when I need to represent a moment in time (the time at which the countdown finishes, for example).
  • 22. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    KonradZuse Explorer
    Currently Being Moderated
    Gotcha, makes sense, thanks!

    Also for some reason I thought in the animation KeyFrame event we could have multiple things going on, but it seems like with my Lambda expression I only get 1 line? Is that Lambda specific, or is that how it works for the KeyFrame events? I'm pretty sure I've seen more than 1 lined event in Lambda before, I don't think it has anything to do with that.


    It seems like when we just do (event) -> it's a single instance compared to


    (MouseEvent evt)
    {
    //etc
    }

    From the API I notice that when we do .setonMousePressed or w/e it uses
     public final void setOnMouseDragged(EventHandler<? super MouseEvent> value)
    which seems to encompass more than the keyFrame which when I try multiple ones says "no sutable constructor for (event) -> {[...]} so not too sure if it's possible, because I have 3 different time labels. 1 updates mins, one seconds/am and one for hours.... I wanted to use the same routine for all, but I think I can create a class, have it extend event, and then pass that as my event right?

    Edited by: KonradZuse on Mar 31, 2013 11:40 AM

    Edited by: KonradZuse on Mar 31, 2013 12:03 PM

    Edited by: KonradZuse on Mar 31, 2013 12:10 PM
  • 23. Re: Calender.getInstance() issue with ScheduledThreadPoolExecutor
    KonradZuse Explorer
    Currently Being Moderated
    James_D wrote:
    I think you can still use the techniques in the code sample jsmith showed.

    Also, if you're using JDK8, there's a nice new time API that is much better than java.util.Calendar.

    For example:
    import java.time.Instant;
    import java.time.Duration; 
    
    import javafx.animation.KeyFrame;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.binding.Bindings;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    
    public class Timer extends Application {
    
         private static final Duration COUNTDOWN_LENGTH = Duration.ofSeconds(60) ;
         
         @Override
         public void start(Stage primaryStage) {
              final Label label = new Label("Press button to start");
              final Button button = new Button("Start");
              final IntegerProperty secondsRemaining = new SimpleIntegerProperty();
              label.textProperty().bind(
                        Bindings.when(secondsRemaining.greaterThan(0))
                        .then(Bindings.format("Seconds remaining: %d", secondsRemaining))
                        .otherwise("Press button to start"));
              button.setOnAction(event -> startTimer(secondsRemaining) );
              button.disableProperty().bind(secondsRemaining.greaterThan(0));
              VBox root = new VBox(5);
              root.getChildren().addAll(label, button);
              Scene scene = new Scene(root, 200, 50);
              primaryStage.setScene(scene);
              primaryStage.show();
         }
         
         private void startTimer(final IntegerProperty secondsRemaining) {
              final Instant finishTime = Instant.now().plus(COUNTDOWN_LENGTH);
              Timeline countdown = new Timeline(
                   new KeyFrame(javafx.util.Duration.ZERO, 
                             (event) -> secondsRemaining.set((int) Duration.between(Instant.now(), finishTime).getSeconds())
                    ),
                   new KeyFrame(javafx.util.Duration.seconds(1))
              );
              countdown.setCycleCount((int)COUNTDOWN_LENGTH.getSeconds());
              countdown.play();
         }
    
         public static void main(String[] args) {
              launch(args);
         }
    }
    Also, to your threading questions:

    Any JavaFX application starts up a thread, called the JavaFX application thread, which is responsible for event handling and UI code. In a JavaFX application, almost all the code you write will be executed on this thread, since it's either in the start() method, or in an event handler. In your original code, you passed a Runnable into a ScheduledThreadPoolExecutor. That class creates new threads for you, and executes your Runnable on them. So now you have multiple threads to worry about.

    The JavaFX animation API also creates new threads, but is JavaFX-friendly in that it provides places where you can supply handlers for various events, such as KeyFrames being reached and the animation finishing. These handlers are invoked on the FX Application thread for you, so you get back to the nice single-threaded feel of the code. Have a look at the "Threads" section in the [url http://docs.oracle.com/javafx/2/architecture/jfxpub-architecture.htm]Architecture and Framework JavaFX tutorial. The [url http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm]Concurrency and Threads tutorial may be useful too, but it's slightly different from the animation-based approach used here.
    I also wanted to say by using this template I ran into a couple of issues.

    1. The timer goes from 59 seconds to 0, not 60.

    2. I sent an event handler for pictures to change at the start, and finish of the timer, and when I do the finish one the timer hits 0, disappears, then the images change back; however my bindings, like setting the visibility of a label only when the timer isn't run, will turn back when the countdown hits 0, and stops.

    It seems as if seconds is really a second fast, and displays it.

    Edited by: KonradZuse on Apr 3, 2013 9:44 PM


    I tried to switch it from the keyFrame @ 1 second and it was just stalling for a second and stay at second 1; however I switched up the code and I got it to work.

       public void timer()
        {
    
              Timeline countdown = new Timeline(
                   new KeyFrame(javafx.util.Duration.ZERO,
                                        (event) ->  seconds.set((int) duration.getSeconds()))
                    ,
                   new KeyFrame(javafx.util.Duration.seconds(1),                         
                                        (event) -> duration = duration.minusSeconds(1))
                                                        
              );
              countdown.setCycleCount((int)duration.getSeconds());
              countdown.play();
                    
                    countdown.setOnFinished((event) -> 
                    {
                                            seconds.set((int) duration.getSeconds());
                                    button.setGraphic(new ImageView(button1));
                                    button.setMouseTransparent(false);
                                    duration = duration.plusSeconds(6);
                imageV.setImage(body1);
                    });
           
        }
    I believe I tried to do this configuration with the between instances and it wasn't working, so I got it to work this way. It seems easier that I just used Duration(which is what I was asking before). I know we were talking before about what to and not to use in terms of updating instances, so I want to make sure this looks good as well.

    I really appreciate all of your help,

    ~KZ
1 2 Previous Next

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points