<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2421237268326151290</id><updated>2012-02-16T01:48:52.883-08:00</updated><title type='text'>Experiments with Java</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://saidandem.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2421237268326151290/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://saidandem.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Sai Pradeep Dandem</name><uri>http://www.blogger.com/profile/02256864179729070156</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-a4xaq-iMh10/ThrslZ9Jv3I/AAAAAAAAEqo/wFZTBEno5rE/s220/DSC00062.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2421237268326151290.post-3554170623651024553</id><published>2012-01-18T09:11:00.000-08:00</published><updated>2012-01-19T08:00:27.357-08:00</updated><title type='text'>Sliding in JavaFX (It’s all about clipping)</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;JavaFX animation package provides many amazinganimation/transition effects. Let’s look into another effect, “Sliding” effect ofnode (relative to the parent node).&amp;nbsp; Theterm ‘relative’ refers to, like the node should hide relatively under theparent node by sliding.If you are familiar with “Titled Pane”, I am speaking about the same effect howthe content of the pane is shown and hide. I am trying to achieve this with some simplelogic and using some properties of a node.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Let’s look into an example, how we can &lt;b style="mso-bidi-font-weight: normal;"&gt;hide/show&lt;/b&gt; our custom nodes by implementing this sliding effect. Inbrief, it is all about clipping our node for some duration of time. There are someamazing blogs/articles available in internet explaining the “clip”functionality of a node. I am going to use this clip feature, to achieve thiseffect.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Below are the screenshots of the example to which thesliding effect is implemented. On click of “Slide Down”, the top pane (bluecolor) content is shown and on click of “Slide Up” the top pane content ishidden.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-i0dV0N9_C0E/TxbyXAzHTVI/AAAAAAAAFEM/AwRh7Kuhu5A/s1600/3stages.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-i0dV0N9_C0E/TxbyXAzHTVI/AAAAAAAAFEM/AwRh7Kuhu5A/s1600/3stages.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Before going into the actual java code, let me explain thelogic pictorially.&amp;nbsp; In the below image,the red color dotted box is the node that is to be shown/hidden by sliding. &amp;nbsp;The grey shaded region is the Rectangle thatis used to clip the node (Means the visible part of node after clipping). Andthe black border box is the parent node.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ouhm9aKBaRk/TxbzHa30YUI/AAAAAAAAFEU/NKZeV7Mw-Fk/s1600/Untitled.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-ouhm9aKBaRk/TxbzHa30YUI/AAAAAAAAFEU/NKZeV7Mw-Fk/s1600/Untitled.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="MsoNormal"&gt;To get this effect we need to handle three parameters (A, B&amp;amp; C as shown in picture)&lt;/div&gt;&lt;div class="MsoNormal"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; A –Start Point of the Node&lt;/div&gt;&lt;div class="MsoNormal"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; B –Start point of the clip rectangle&lt;/div&gt;&lt;div class="MsoNormal"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; C –Height of the clip rectangle.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Considering the above scenario the code to slide up (hide)the node(topPane) is as below.&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush: java; title: ; notranslate" title=""&gt;Rectangle2D boxBounds = new Rectangle2D(100, 100, 250, 250);&lt;br /&gt;Rectangle clipRect = new Rectangle();&lt;br /&gt;clipRect.setWidth(boxBounds.getWidth());&lt;br /&gt;&lt;br /&gt;StackPane topPane = new StackPane();&lt;br /&gt;topPane.setPrefSize( boxBounds.getWidth(),boxBounds.getHeight());  topPane.setClip(clipRect);&lt;br /&gt;                &lt;br /&gt;/* Animation for scroll up. */&lt;br /&gt;Timeline timelineUp = new Timeline();&lt;br /&gt;timelineUp.setCycleCount(1); &lt;br /&gt;timelineUp.setAutoReverse(true);&lt;br /&gt;&lt;br /&gt;final KeyValue kvUp1 = new KeyValue(clipRect.heightProperty(), 0);&lt;br /&gt;final KeyValue kvUp2 = new KeyValue(clipRect.translateYProperty(), boxBounds.getHeight());&lt;br /&gt;final KeyValue kvUp3 = new KeyValue(topPane.translateYProperty(), -boxBounds.getHeight());&lt;br /&gt;final KeyFrame kfUp = new KeyFrame(Duration.millis(200), kvUp1, kvUp2, kvUp3);&lt;br /&gt;&lt;br /&gt;timelineUp.getKeyFrames().add(kfUp);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;In the above code, for the given amount of duration,&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Clip rectangle &lt;b&gt;heightProperty &lt;/b&gt;is decreased to 0,&lt;/li&gt;&lt;li&gt;&lt;b&gt;translateYProperty &lt;/b&gt;of clip Rectangle is moved down to amount of height of the node and&lt;/li&gt;&lt;li&gt;&lt;b&gt;translateYProperty &lt;/b&gt;of node is moved up to the amount of  height of the node.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Similarly the code to slide down (show) the node (topPane) is as below &lt;/div&gt;&lt;br /&gt;&lt;pre class="brush: java; title: ; notranslate" title=""&gt;/* Animation for scroll down. */&lt;br /&gt;Timeline timelineDown = new Timeline();&lt;br /&gt;timelineDown.setCycleCount(1);&lt;br /&gt;timelineDown.setAutoReverse(true);&lt;br /&gt;&lt;br /&gt;final KeyValue kvDwn1 = new KeyValue(clipRect.heightProperty(), boxBounds.getHeight());&lt;br /&gt;final KeyValue kvDwn2 = new KeyValue(clipRect.translateYProperty(), 0);&lt;br /&gt;final KeyValue kvDwn3 = new KeyValue(topPane.translateYProperty(), 0);&lt;br /&gt;final KeyFrame kfDwn = new KeyFrame(Duration.millis(200), kvDwn1, kvDwn2, kvDwn3);&lt;br /&gt;&lt;br /&gt;timelineDown.getKeyFrames().add(kfDwn);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;In the above code, for the given amount of duration,&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Clip rectangle &lt;b&gt;heightProperty &lt;/b&gt;is to the height of the node,&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;translateYProperty &lt;/b&gt;of clip Rectangle is moved up  to 0 and&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;translateYProperty &lt;/b&gt;of node is moved down to 0.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;Combining all the logic together, below is the final &lt;b&gt;SSCCE &lt;/b&gt;(&lt;b&gt;S&lt;/b&gt;hort, &lt;b&gt;S&lt;/b&gt;elf &lt;b&gt;C&lt;/b&gt;ontained, &lt;b&gt;C&lt;/b&gt;orrect &lt;b&gt;E&lt;/b&gt;xample) code of the above example.&lt;br /&gt;&lt;pre class="brush: java; title: ; notranslate" title=""&gt;import javafx.animation.KeyFrame;&lt;br /&gt;import javafx.animation.KeyValue;&lt;br /&gt;import javafx.animation.Timeline;&lt;br /&gt;import javafx.application.Application;&lt;br /&gt;import javafx.event.ActionEvent;&lt;br /&gt;import javafx.event.EventHandler;&lt;br /&gt;import javafx.geometry.Pos;&lt;br /&gt;import javafx.geometry.Rectangle2D;&lt;br /&gt;import javafx.scene.Group;&lt;br /&gt;import javafx.scene.Scene;&lt;br /&gt;import javafx.scene.control.Button;&lt;br /&gt;import javafx.scene.layout.HBox;&lt;br /&gt;import javafx.scene.layout.StackPane;&lt;br /&gt;import javafx.scene.layout.VBox;&lt;br /&gt;import javafx.scene.paint.Color;&lt;br /&gt;import javafx.scene.paint.CycleMethod;&lt;br /&gt;import javafx.scene.paint.LinearGradient;&lt;br /&gt;import javafx.scene.paint.Stop;&lt;br /&gt;import javafx.scene.shape.Rectangle;&lt;br /&gt;import javafx.scene.shape.RectangleBuilder;&lt;br /&gt;import javafx.scene.text.Font;&lt;br /&gt;import javafx.scene.text.TextBuilder;&lt;br /&gt;import javafx.stage.Stage;&lt;br /&gt;import javafx.util.Duration;&lt;br /&gt;&lt;br /&gt;public class SlideEffectDemo extends Application {&lt;br /&gt;&lt;br /&gt; private Rectangle2D boxBounds = new Rectangle2D(100, 100, 250, 200);&lt;br /&gt; &lt;br /&gt; private StackPane bottomPane;&lt;br /&gt; private StackPane topPane;&lt;br /&gt; private Rectangle clipRect;&lt;br /&gt; private Timeline timelineUp;&lt;br /&gt; private Timeline timelineDown;&lt;br /&gt; &lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;  Application.launch(args);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; @Override&lt;br /&gt; public void start(Stage stage) throws Exception {&lt;br /&gt;  VBox root = new VBox();&lt;br /&gt;  root.setAlignment(Pos.CENTER);&lt;br /&gt;  root.autosize();&lt;br /&gt;  Scene scene = new Scene(root);&lt;br /&gt;  stage.setTitle("Slide Effect Demo");&lt;br /&gt;  stage.setWidth(350);&lt;br /&gt;     stage.setHeight(300);&lt;br /&gt;     stage.setScene(scene);&lt;br /&gt;     stage.show();&lt;br /&gt;     &lt;br /&gt;  configureBox(root);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private void configureBox(VBox root) {&lt;br /&gt;  StackPane container = new StackPane();&lt;br /&gt;  container.setPrefHeight(250);&lt;br /&gt;  container.setPrefSize(boxBounds.getWidth(), boxBounds.getHeight());&lt;br /&gt;  container.setStyle("-fx-border-width:1px;-fx-border-style:solid;-fx-border-color:#999999;");&lt;br /&gt;  &lt;br /&gt;  // BOTTOM PANE &lt;br /&gt;  Stop[] stops = new Stop[] { new Stop(0, Color.web("#F89C8C")), new Stop(1, Color.web("#BE250A"))};&lt;br /&gt;  LinearGradient lg = new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, stops);&lt;br /&gt;  bottomPane = new StackPane();&lt;br /&gt;  bottomPane.getChildren().addAll(RectangleBuilder.create().width(boxBounds.getWidth()).height(boxBounds.getHeight()).fill(lg).build(), &lt;br /&gt;     TextBuilder.create().text("Click the above \"Slide Down\" button to see the top pane content...").wrappingWidth(200).font(Font.font("Arial", 22)).build());&lt;br /&gt;  &lt;br /&gt;  // TOP PANE &lt;br /&gt;  Stop[] stops2 = new Stop[] { new Stop(0, Color.web("#FFFFFF")), new Stop(1, Color.web("#50AABC"))};&lt;br /&gt;  LinearGradient lg2 = new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, stops2);&lt;br /&gt;  StackPane sp1 = new StackPane();&lt;br /&gt;  sp1.getChildren().add(TextBuilder.create().text("Click the below \"Slide Up\" button to see the bottom pane content...").wrappingWidth(200).font(Font.font("Arial", 22)).build());&lt;br /&gt;  &lt;br /&gt;  topPane = new StackPane();&lt;br /&gt;  topPane.getChildren().addAll(RectangleBuilder.create().width(boxBounds.getWidth()).height(boxBounds.getHeight()).fill(lg2).build(), sp1);&lt;br /&gt;  container.getChildren().addAll(bottomPane,topPane);&lt;br /&gt;  &lt;br /&gt;  setAnimation();&lt;br /&gt;  &lt;br /&gt;  Group gp = new Group();&lt;br /&gt;  gp.getChildren().add(container);&lt;br /&gt;  root.getChildren().addAll(getActionPane(),gp);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private void setAnimation(){&lt;br /&gt;  // Initially hiding the Top Pane&lt;br /&gt;  clipRect = new Rectangle();&lt;br /&gt;        clipRect.setWidth(boxBounds.getWidth());&lt;br /&gt;  clipRect.setHeight(0);&lt;br /&gt;  clipRect.translateYProperty().set(boxBounds.getHeight());&lt;br /&gt;  topPane.setClip(clipRect);&lt;br /&gt;  topPane.translateYProperty().set(-boxBounds.getHeight());&lt;br /&gt;  &lt;br /&gt;  // Animation for bouncing effect.&lt;br /&gt;  final Timeline timelineBounce = new Timeline();&lt;br /&gt;  timelineBounce.setCycleCount(2);&lt;br /&gt;  timelineBounce.setAutoReverse(true);&lt;br /&gt;  final KeyValue kv1 = new KeyValue(clipRect.heightProperty(), (boxBounds.getHeight()-15));&lt;br /&gt;  final KeyValue kv2 = new KeyValue(clipRect.translateYProperty(), 15);&lt;br /&gt;  final KeyValue kv3 = new KeyValue(topPane.translateYProperty(), -15);&lt;br /&gt;  final KeyFrame kf1 = new KeyFrame(Duration.millis(100), kv1, kv2, kv3);&lt;br /&gt;  timelineBounce.getKeyFrames().add(kf1);&lt;br /&gt;  &lt;br /&gt;  // Event handler to call bouncing effect after the scroll down is finished.&lt;br /&gt;  EventHandler&lt;actionevent&gt; onFinished = new EventHandler&lt;actionevent&gt;() {&lt;br /&gt;            public void handle(ActionEvent t) {&lt;br /&gt;             timelineBounce.play();&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;        &lt;br /&gt;        timelineDown = new Timeline();&lt;br /&gt;        timelineUp = new Timeline();&lt;br /&gt;        &lt;br /&gt;        // Animation for scroll down.&lt;br /&gt;  timelineDown.setCycleCount(1);&lt;br /&gt;  timelineDown.setAutoReverse(true);&lt;br /&gt;  final KeyValue kvDwn1 = new KeyValue(clipRect.heightProperty(), boxBounds.getHeight());&lt;br /&gt;  final KeyValue kvDwn2 = new KeyValue(clipRect.translateYProperty(), 0);&lt;br /&gt;  final KeyValue kvDwn3 = new KeyValue(topPane.translateYProperty(), 0);&lt;br /&gt;  final KeyFrame kfDwn = new KeyFrame(Duration.millis(200), onFinished, kvDwn1, kvDwn2, kvDwn3);&lt;br /&gt;  timelineDown.getKeyFrames().add(kfDwn);&lt;br /&gt;  &lt;br /&gt;  // Animation for scroll up.&lt;br /&gt;  timelineUp.setCycleCount(1); &lt;br /&gt;  timelineUp.setAutoReverse(true);&lt;br /&gt;  final KeyValue kvUp1 = new KeyValue(clipRect.heightProperty(), 0);&lt;br /&gt;  final KeyValue kvUp2 = new KeyValue(clipRect.translateYProperty(), boxBounds.getHeight());&lt;br /&gt;  final KeyValue kvUp3 = new KeyValue(topPane.translateYProperty(), -boxBounds.getHeight());&lt;br /&gt;  final KeyFrame kfUp = new KeyFrame(Duration.millis(200), kvUp1, kvUp2, kvUp3);&lt;br /&gt;  timelineUp.getKeyFrames().add(kfUp);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; private HBox getActionPane(){&lt;br /&gt;  HBox hb = new HBox();&lt;br /&gt;  hb.setAlignment(Pos.CENTER);&lt;br /&gt;  hb.setSpacing(10);&lt;br /&gt;  hb.setPrefHeight(40);&lt;br /&gt;  Button upBtn = new Button("Slide Up");&lt;br /&gt;  upBtn.setOnAction(new EventHandler&lt;actionevent&gt;() {&lt;br /&gt;   @Override&lt;br /&gt;   public void handle(ActionEvent arg0) {&lt;br /&gt;    timelineUp.play();&lt;br /&gt;   }&lt;br /&gt;  });&lt;br /&gt;  Button downBtn = new Button("Slide Down");&lt;br /&gt;  downBtn.setOnAction(new EventHandler&lt;actionevent&gt;() {&lt;br /&gt;   @Override&lt;br /&gt;   public void handle(ActionEvent arg0) {&lt;br /&gt;    timelineDown.play();&lt;br /&gt;   }&lt;br /&gt;  });&lt;br /&gt;  hb.getChildren().addAll(downBtn,upBtn);&lt;br /&gt;  return hb;&lt;br /&gt; }&lt;br /&gt;}&lt;/actionevent&gt;&lt;/actionevent&gt;&lt;/actionevent&gt;&lt;/actionevent&gt;&lt;/pre&gt;&lt;div class="MsoNormal"&gt;If you observe in the above code, an extra &lt;b&gt;timelineBounce &lt;/b&gt;is added to show the bounce effect when the top pane slides down.&lt;br /&gt;&lt;br /&gt;A more realistic example of this slide effect can be found &lt;b&gt;&lt;a href="https://gist.github.com/95accfa4d8de8b9b3310" target="_blank"&gt;here&lt;/a&gt;&lt;/b&gt;.&lt;br /&gt;Below are the screenshots of this example.The search form slides downwards and upwards on click of the “Search” label.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-_bHd4rtB-l8/Txb7kOCYs2I/AAAAAAAAFEc/k-RRiRG4eAQ/s1600/employeebefore.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="253" src="http://2.bp.blogspot.com/-_bHd4rtB-l8/Txb7kOCYs2I/AAAAAAAAFEc/k-RRiRG4eAQ/s400/employeebefore.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-4XIW9YIbyKA/Txb8QEoKjtI/AAAAAAAAFEk/mIEDzExQXdY/s1600/employeeafter.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="253" src="http://4.bp.blogspot.com/-4XIW9YIbyKA/Txb8QEoKjtI/AAAAAAAAFEk/mIEDzExQXdY/s400/employeeafter.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I hope you can relate the similar logic to slide the node towards LEFT and RIGHT, by using the &lt;b&gt;widthProperty &lt;/b&gt;and &lt;b&gt;translateXProperty &lt;/b&gt;of the node.&lt;br /&gt;&lt;br /&gt;Happy Coding!!&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2421237268326151290-3554170623651024553?l=saidandem.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://saidandem.blogspot.com/feeds/3554170623651024553/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://saidandem.blogspot.com/2012/01/sliding-in-javafx-its-all-about.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2421237268326151290/posts/default/3554170623651024553'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2421237268326151290/posts/default/3554170623651024553'/><link rel='alternate' type='text/html' href='http://saidandem.blogspot.com/2012/01/sliding-in-javafx-its-all-about.html' title='Sliding in JavaFX (It’s all about clipping)'/><author><name>Sai Pradeep Dandem</name><uri>http://www.blogger.com/profile/02256864179729070156</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-a4xaq-iMh10/ThrslZ9Jv3I/AAAAAAAAEqo/wFZTBEno5rE/s220/DSC00062.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-i0dV0N9_C0E/TxbyXAzHTVI/AAAAAAAAFEM/AwRh7Kuhu5A/s72-c/3stages.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2421237268326151290.post-1406444871427552026</id><published>2012-01-05T09:20:00.001-08:00</published><updated>2012-01-05T11:02:50.871-08:00</updated><title type='text'>Percent Width for TableColumn in JavaFX 2.x TableView</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;The moment I started working with TableView in JavaFX 2.x, the first question raised in my mind is “Why there is no feature of setting the column widths in percentage as we do in HTML?”  I am not sure what could be the reasons for not setting this feature. But if my  application demands, I have to implement this by somehow ;).  Ofcourse there are a couple of issues logged in JIRA&amp;nbsp; related to this functionality, but till it get resolved here is the way (workaround) how I tried to get it.&lt;br /&gt;&lt;br /&gt;And another thing is with the display of “Extra Column” in TableView.  I still remember, in the discussion forum, one guy has referred this term as “Ghost Column” :). Below is the screen shot of a simple TableView, with  some setting of &lt;b&gt;prefWidth&lt;/b&gt;(here 150px)  to TableColumns and resize the screen.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Iz7_dMJBln8/TwXeUgZhDVI/AAAAAAAAFDg/qzQKqaUEJAM/s1600/table1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-Iz7_dMJBln8/TwXeUgZhDVI/AAAAAAAAFDg/qzQKqaUEJAM/s1600/table1.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;Ok, let me get into some action...&amp;nbsp; The target is, on resizing the window thetable columns should keep their relative sizes with respect to container/window.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;For achieving this I am taking the help of &lt;b style="mso-bidi-font-weight: normal;"&gt;GridPane &lt;/b&gt;for which percentage widths canbe set to its columns through ColumnConstraints.&lt;/div&gt;&lt;br /&gt;As a first step, a &lt;b style="mso-bidi-font-weight: normal;"&gt;CustomTableColumn&lt;/b&gt;class is created that extends &lt;b style="mso-bidi-font-weight: normal;"&gt;TableColumn&lt;/b&gt;,to hold the custom &lt;b style="mso-bidi-font-weight: normal;"&gt;percentWidth&lt;/b&gt;property for the column.&lt;br /&gt;&lt;div class="MsoNormal"&gt;The code for the CustomTableColumn is as below:&lt;/div&gt;&lt;script class="brush: java" type="syntaxhighlighter"&gt;&lt;![CDATA[/** * CustomTableColumn to hold the custom percentWidth property. */public class CustomTableColumn&lt;S,T&gt; extends TableColumn&lt;S, T&gt;{ private SimpleDoubleProperty percentWidth = new SimpleDoubleProperty(); public CustomTableColumn(String columnName){  super(columnName); } public SimpleDoubleProperty percentWidth() {  return percentWidth; } public double getPercentWidth() {  return percentWidth.get(); } public void setPercentWidth(double percentWidth) {  this.percentWidth.set(percentWidth); }}]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;div class="MsoNormal"&gt;The idea is that, we will create a container, probably aStackPane (&lt;b style="mso-bidi-font-weight: normal;"&gt;CustomTableView&lt;/b&gt;) whichholds a &lt;b style="mso-bidi-font-weight: normal;"&gt;GridPane&lt;/b&gt; and a &lt;b style="mso-bidi-font-weight: normal;"&gt;TableView&lt;/b&gt;. &amp;nbsp;The number of columns in the GridPane will besynchronized with the number of columns in the TableView.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&amp;nbsp;StackPane is used asthe content in each column of the grid. (StackPane because, it fitsautomatically to its parent size)&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Now the core logic is, &lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;u&gt;&lt;i&gt;Step 1&lt;/i&gt;&lt;/u&gt; : We will be creating ColumnConstraints with thepercentWidth that is specified for each column(CustomTableColumn) of theTableView. And set these ColumnConstraints to the grid.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;u&gt;&lt;i&gt;Step 2&lt;/i&gt;&lt;/u&gt; : The next step is binding each StackPane’s&amp;nbsp; &lt;b style="mso-bidi-font-weight: normal;"&gt;widthProperty&lt;/b&gt;to its corresponding table column’s &lt;b style="mso-bidi-font-weight: normal;"&gt;prefWidthProperty&lt;/b&gt;.&amp;nbsp;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%;"&gt;Considering the above logic, the CustomTableViewcode is as below:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;script class="brush: java" type="syntaxhighlighter"&gt;&lt;![CDATA[/** * CustomTableView to hold the table and grid. */public class CustomTableView&lt;s&gt; extends StackPane{ private TableView&lt;s&gt; table;  @SuppressWarnings("rawtypes") public CustomTableView(){  this.table = new TableView&lt;s&gt;();  final GridPane grid = new GridPane();  this.table.getColumns().addListener(new ListChangeListener&lt;tablecolumn&gt;(){   @Override   public void onChanged(javafx.collections.ListChangeListener.Change&lt;? extends TableColumn&gt; arg0) {    grid.getColumnConstraints().clear();    ColumnConstraints[] arr1 = new ColumnConstraints[CustomTableView.this.table.getColumns().size()];    StackPane[] arr2 = new StackPane[CustomTableView.this.table.getColumns().size()];    int i=0;    for(TableColumn column : CustomTableView.this.table.getColumns()){     CustomTableColumn col = (CustomTableColumn)column;     ColumnConstraints consta = new ColumnConstraints();     consta.setPercentWidth(col.getPercentWidth());          StackPane sp = new StackPane();     if(i==0){      // Quick fix for not showing the horizantal scroll bar.      NumberBinding diff = sp.widthProperty().subtract(3.75);       column.prefWidthProperty().bind(diff);     }else{      column.prefWidthProperty().bind(sp.widthProperty());     }     arr1[i] = consta;     arr2[i] = sp;     i++;    }    grid.getColumnConstraints().addAll(arr1);    grid.addRow(0, arr2);   }  });  getChildren().addAll(grid,table); }  public TableView&lt;s&gt; getTableView(){  return this.table; }}]]&gt;&lt;/script&gt;&lt;br /&gt;Combining all the above code, the below is the final &lt;b&gt;SSCCE&lt;/b&gt;(&lt;b&gt;S&lt;/b&gt;hort, &lt;b&gt;S&lt;/b&gt;elf &lt;b&gt;C&lt;/b&gt;ontained, &lt;b&gt;C&lt;/b&gt;orrect &lt;b&gt;E&lt;/b&gt;xample) code:&lt;br /&gt;&lt;script class="brush: java" type="syntaxhighlighter"&gt;&lt;![CDATA[import javafx.application.Application;import javafx.beans.binding.NumberBinding;import javafx.beans.property.SimpleDoubleProperty;import javafx.beans.property.SimpleStringProperty;import javafx.collections.FXCollections;import javafx.collections.ListChangeListener;import javafx.collections.ObservableList;import javafx.scene.Scene;import javafx.scene.control.TableColumn;import javafx.scene.control.TableView;import javafx.scene.control.cell.PropertyValueFactory;import javafx.scene.layout.ColumnConstraints;import javafx.scene.layout.GridPane;import javafx.scene.layout.StackPane;import javafx.stage.Stage;public class TableViewAutoSizeDemo extends Application { public static void main(String[] args) {  Application.launch(args); }  @Override public void start(Stage stage) throws Exception {  StackPane root = new StackPane();  root.autosize();  Scene scene = new Scene(root);  stage.setTitle("TableView Auto Size Demo");  stage.setWidth(700);     stage.setHeight(400);     stage.setScene(scene);     stage.show();       configureTable(root); } @SuppressWarnings("unchecked") private void configureTable(StackPane root) {    final ObservableList&lt;mydomain&gt; data = FXCollections.observableArrayList(     new MyDomain("Apple","This is a fruit.","Red"),     new MyDomain("Orange","This is also a fruit.","Orange"),     new MyDomain("Potato","This is a vegetable.","Brown")     );    CustomTableView&lt;mydomain&gt; table = new CustomTableView&lt;mydomain&gt;();    CustomTableColumn&lt;MyDomain,String&gt; titleColumn = new CustomTableColumn&lt;MyDomain,String&gt;("Title");  titleColumn.setPercentWidth(25);  titleColumn.setCellValueFactory(new PropertyValueFactory&lt;MyDomain,String&gt;("name"));    CustomTableColumn&lt;MyDomain,String&gt; descCol = new CustomTableColumn&lt;MyDomain,String&gt;("Description");  descCol.setPercentWidth(55);  descCol.setCellValueFactory(new PropertyValueFactory&lt;MyDomain,String&gt;("description"));    CustomTableColumn&lt;MyDomain,String&gt; colorCol = new CustomTableColumn&lt;MyDomain,String&gt;("Color");  colorCol.setPercentWidth(20);  colorCol.setCellValueFactory(new PropertyValueFactory&lt;MyDomain,String&gt;("color"));    table.getTableView().getColumns().addAll(titleColumn,descCol,colorCol);  table.getTableView().setItems(data);  root.getChildren().add(table); } /**  * CustomTableView to hold the table and grid.  */ public class CustomTableView&lt;s&gt; extends StackPane{  private TableView&lt;s&gt; table;    @SuppressWarnings("rawtypes")  public CustomTableView(){   this.table = new TableView&lt;s&gt;();   final GridPane grid = new GridPane();   this.table.getColumns().addListener(new ListChangeListener&lt;tablecolumn&gt;(){    @Override    public void onChanged(javafx.collections.ListChangeListener.Change&lt;? extends TableColumn&gt; arg0) {      grid.getColumnConstraints().clear();     ColumnConstraints[] arr1 = new ColumnConstraints[CustomTableView.this.table.getColumns().size()];     StackPane[] arr2 = new StackPane[CustomTableView.this.table.getColumns().size()];     int i=0;     for(TableColumn column : CustomTableView.this.table.getColumns()){      CustomTableColumn col = (CustomTableColumn)column;      ColumnConstraints consta = new ColumnConstraints();      consta.setPercentWidth(col.getPercentWidth());            StackPane sp = new StackPane();      if(i==0){       // Quick fix for not showing the horizantal scroll bar.       NumberBinding diff = sp.widthProperty().subtract(3.75);        column.prefWidthProperty().bind(diff);      }else{       column.prefWidthProperty().bind(sp.widthProperty());      }      arr1[i] = consta;      arr2[i] = sp;      i++;     }     grid.getColumnConstraints().addAll(arr1);     grid.addRow(0, arr2);    }   });   getChildren().addAll(grid,table);  }    public TableView&lt;s&gt; getTableView(){   return this.table;  } }  /**  * CustomTableColumn to hold the custom percentWidth property.  */ public class CustomTableColumn&lt;S,T&gt; extends TableColumn&lt;S, T&gt;{  private SimpleDoubleProperty percentWidth = new SimpleDoubleProperty();  public CustomTableColumn(String columnName){   super(columnName);  }  public SimpleDoubleProperty percentWidth() {   return percentWidth;  }  public double getPercentWidth() {   return percentWidth.get();  }  public void setPercentWidth(double percentWidth) {   this.percentWidth.set(percentWidth);  } }  /**  * Domain Object.  */ public class MyDomain{  private SimpleStringProperty name = new SimpleStringProperty();  private SimpleStringProperty description = new SimpleStringProperty();  private SimpleStringProperty color = new SimpleStringProperty();  public MyDomain(String name, String desc,String color){   this.name.set(name);   this.description.set(desc);   this.color.set(color);  }  public String getDescription() {      return description.get();  }        public SimpleStringProperty descriptionProperty(){      return description;  }       public String getName() {      return name.get();  }       public SimpleStringProperty nameProperty(){      return name;  }       public String getColor() {      return color.get();  }       public SimpleStringProperty colorProperty(){      return color;  } }}]]&gt;&lt;/script&gt;&lt;br /&gt;On resizing the window, the output is as below. Not only the columns have maintained their relative sizes , but the extra column is no more visible. :)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-RJdd1JQfuGM/TwXqx8IyLXI/AAAAAAAAFEE/CfoPBC39NFE/s1600/table2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-RJdd1JQfuGM/TwXqx8IyLXI/AAAAAAAAFEE/CfoPBC39NFE/s1600/table2.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I hope the above logic will serve the need till the auto sizing feature of TableView is implemented and released.&lt;br /&gt;&lt;br /&gt;Happy Coding!! :)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;Note: The above logic/code may be or can be improvised. Let me also know the changes for better implementation. :)&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2421237268326151290-1406444871427552026?l=saidandem.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://saidandem.blogspot.com/feeds/1406444871427552026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://saidandem.blogspot.com/2012/01/percent-width-for-tablecolumn-in-javafx.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2421237268326151290/posts/default/1406444871427552026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2421237268326151290/posts/default/1406444871427552026'/><link rel='alternate' type='text/html' href='http://saidandem.blogspot.com/2012/01/percent-width-for-tablecolumn-in-javafx.html' title='Percent Width for TableColumn in JavaFX 2.x TableView'/><author><name>Sai Pradeep Dandem</name><uri>http://www.blogger.com/profile/02256864179729070156</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-a4xaq-iMh10/ThrslZ9Jv3I/AAAAAAAAEqo/wFZTBEno5rE/s220/DSC00062.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-Iz7_dMJBln8/TwXeUgZhDVI/AAAAAAAAFDg/qzQKqaUEJAM/s72-c/table1.jpg' height='72' width='72'/><thr:total>3</thr:total></entry></feed>
