{"id":112,"date":"2009-03-14T13:11:31","date_gmt":"2009-03-14T20:11:31","guid":{"rendered":"http:\/\/www.connorgarvey.com\/blog\/?p=112"},"modified":"2009-03-27T20:35:47","modified_gmt":"2009-03-28T03:35:47","slug":"simple-javafx-spinner-using-a-timeline","status":"publish","type":"post","link":"https:\/\/connorgarvey.com\/blog\/?p=112","title":{"rendered":"Simple JavaFX Spinner Using a Timeline"},"content":{"rendered":"<p>I&#8217;ve been working on a demonstration JavaFX application.\u00a0 It was originaly written for the prerelease candidate.\u00a0 I just updated it to work with JavaFX version 1.1 and thought I&#8217;d share it.\u00a0 This is a simple spinner that can be stopped and started.\u00a0 Here&#8217;s the full source.\u00a0 A description of how it works is below.<\/p>\n<pre>package org.mediabrowser;\r\n\r\nimport javafx.animation.KeyFrame;\r\nimport javafx.animation.Timeline;\r\nimport javafx.scene.CustomNode;\r\nimport javafx.scene.Group;\r\nimport javafx.scene.image.ImageView;\r\nimport javafx.scene.image.Image;\r\nimport javafx.scene.Node;\r\nimport javafx.scene.shape.Rectangle;\r\nimport javafx.scene.transform.Rotate;\r\n\r\n\/**\r\n * A spinning icon, indicating the application is working\r\n * @author Connor Garvey\r\n * @created Oct 22, 2008, 8:12:48 PM\r\n * @version 0.0.2\r\n * @since 0.0.1\r\n *\/\r\n\r\npublic class Spinner extends CustomNode {\r\n  var rotation: Number = 0;\r\n  var timeline: Timeline = Timeline {\r\n    repeatCount: Timeline.INDEFINITE;\r\n    keyFrames: [\r\n      KeyFrame {\r\n        time: 50ms\r\n        action: tick\r\n      }\r\n    ]\r\n  };\r\n\r\n  public override function create(): Node {\r\n    return Group {\r\n      content: [\r\n        ImageView {\r\n          image: Image {\r\n            url: \"{__DIR__}resources\/color_wheel.png\"\r\n          }\r\n          transforms: Rotate {\r\n            pivotX: 8\r\n            pivotY: 8\r\n            angle: bind this.rotation\r\n          }\r\n          translateX: 3\r\n          translateY: 3\r\n        },\r\n        Rectangle {\r\n          width: 22\r\n          height: 22\r\n        }\r\n      ]\r\n    };\r\n  }\r\n\r\n  public function start() {\r\n    this.timeline.play();\r\n  }\r\n\r\n  public function stop() {\r\n    this.timeline.stop();\r\n  }\r\n\r\n  function tick() {\r\n    this.rotation += 20;\r\n    if (this.rotation == 360) {\r\n      this.rotation = 0;\r\n    }\r\n  }\r\n}<\/pre>\n<ul>\n<li>First, the spinner extends CustomNode.  That way, it can be placed anywhere in a UI.<\/li>\n<li>The timeline is used to rotate the spinner\n<ul>\n<li>Since the application will be starting and stopping the spinner, set it to run forever, Timeline.INDEFINITE<\/li>\n<li>The spinner only does one thing, turn, so it only needs one key frame.\u00a0 It&#8217;s set to turn 20 degrees every 50ms.<\/li>\n<\/ul>\n<\/li>\n<li>JavaFX will call create() to create instances of the spinner\n<ul>\n<li>The __DIR__ makes the spinner image relative to the current class<\/li>\n<li>Since the image is 16&#215;16, set the rotation pivot point to 8&#215;8, the center of the image<\/li>\n<li>The angle of rotation is bound to a property of the class so that it can be easily modified<\/li>\n<li>When an image starts to rotate, it appears to shake because it&#8217;s not round.\u00a0 To smooth the rotation out, it&#8217;s transformed down and to the right and placed inside of a rectangle.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been working on a demonstration JavaFX application.\u00a0 It was originaly written for the prerelease candidate.\u00a0 I just updated it to work with JavaFX version 1.1 and thought I&#8217;d share it.\u00a0 This is a simple spinner that can be stopped and started.\u00a0 Here&#8217;s the full source.\u00a0 A description of how it works is below. package [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[61],"tags":[9,25,5,7,16],"class_list":["post-112","post","type-post","status-publish","format-standard","hentry","category-javafx","tag-image","tag-javafx","tag-programming","tag-redpoint","tag-source"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1ql2n-1O","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/112","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=112"}],"version-history":[{"count":6,"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/112\/revisions"}],"predecessor-version":[{"id":115,"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/112\/revisions\/115"}],"wp:attachment":[{"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=112"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=112"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/connorgarvey.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}