TweetWallFX – Part 3

Hi,

Comparing to the two first parts, this article is going to propose some tips as well as some ideas that maybe could be interesting to see in JavaFX (JavaFX team members, keep reading). Well it seems to be cleared that since I took a look int JavaFX at Devoxx France I became a true fan (JavaFX team members: you simply rock by creating this version 2)! And when you start looking at it, just be honest, it’s an amazing technology! I’ll be talking in this article about transitions and FXMLLoader. Those topics are used in TweetWallFX to simplify some developments.

Transitions and animations

Since JavaFX 1 it is possible to create some transitions, animations on Node: fade in/out effects, sequential transition, rotations, scale, … and very complex ones! JFX is kind of open. Let’s take an example of fade in/out animation:

Label label = new Label("Fade me in");
// Create a transition that will apply on the label and during 1 second
FadeTransition fadeIn = new FadeTransition(new Duration(1000), label);
fadeIn.setFromValue(0);
fadeIn.setToValue(1.0);
// Go!
fadeIn.play();

label.setText("Fade me out");
FadeTransition fadeOut = new FadeTransition(new Duration(1000), label);
fadeOut.setFromValue(1.0);
fadeOut.setToValue(0);
fadeOut.play();

Well, the fade in and out code are the same except the From and To values. So let’s make it more scalable and in the way to be some “utils” methods.

public static void fadeOut(Node node, double duration) {
  getFadeOutAnimation(node, duration).play();
}

public static void fadeIn(Node node, double duration) {
  getFadeInAnimation(node, duration).play();
}

public static FadeTransition getFadeInAnimation(Node node, double duration) {
  return getFadeAnimation(node, duration, node.getOpacity(), 1.0);
}

public static FadeTransition getFadeOutAnimation(Node node, double duration) {
  return getFadeAnimation(node, duration, node.getOpacity(), 0.0);
}

private static FadeTransition getFadeAnimation(Node node, double duration, double fromValue, double toValue) {
  FadeTransition fadeTransition = new FadeTransition(new Duration(duration),
                node);
  fadeTransition.setFromValue(fromValue);
  fadeTransition.setToValue(toValue);
  return fadeTransition;
}

Easy right? As you can see, the fromValue is the current opacity of the Node because the FadeTransition is updating this value while the transition is played. So instead of asking everytime the from value, we just take the current opacity, which seems logical.
Now on the same basis we will create a simple transition which will translate a Node horizontally and/or vertically.

/** We will move the node from the given number of horizontal and vertical pixels */
public static void move(Node node, double duration, double numberOfHorizontalPixels, double numberOfVerticalPixels) {
  getMoveAnimation(node, duration, numberOfHorizontalPixels, numberOfVerticalPixels).play();
}

public static Timeline getMoveAnimation(Node node, double duration, double numberOfHorizontalPixels, double numberOfVerticalPixels) {
  KeyValue horizontalMove = null, verticalMove = null;

  if (numberOfHorizontalPixels != 0) {
    // This represents the final horizontal position of the Node:
    // Current position + "deltaX"
    horizontalMove = new KeyValue(node.layoutXProperty(),
                     node.getLayoutX() + numberOfHorizontalPixels);
  }
  if (numberOfVerticalPixels != 0) {
    // This represents the final vertical position of the Node
    // Current position + "deltaY"
    verticalMove = new KeyValue(node.layoutYProperty(),
                   node.getLayoutY() + numberOfVerticalPixels);
  }
  // KeyFrame are like the interpolation frames in Flash ...
  KeyFrame kf = new KeyFrame(new Duration(duration), horizontalMove, verticalMove);
  // The timeline will play every given KeyFrame
  Timeline timeline = new Timeline(kf);
  // Play the animation once
  timeline.setCycleCount(1);

  return timeline;
}

If you are familiar with Flash development, you may recognize some concepts here. The timeline is globally the same as the timeline in Flash. The KeyFrame is a developer defined position of an object, defined by KeyValues. In Flash, you will do an interpolation, and the last image of this interpolation is defined by you, developer. And the intermediate images (frames) are managed and computed by the engine. In JavaFX, same concept. If you’re more interested in the animations, there’re some others that you can read on the JavaFX page.

FXMLLoader

FXML files are loaded using a FXMLLoader. You have two main ways of loading such files. The first one is using the static load() method which will return you the root component of your FXML file.

// I don't manage exceptions in this example
URL url = getClass().getResource("/some/package/yourFile.fxml");
Parent root = FXMLLoader.load(url);

This is useful when you don’t really need the controller. The second way is to create an instance of FXMLLoader that allows you to, of course, get the root element of your file, as well as the controller.

// I don't manage exceptions in this example
URL url = getClass().getResource("/some/package/yourFile.fxml");
FXMLLoader loader = new FXMLLoader(url);
Object root = loader.load();
Object controller = loader.getController();

Pretty straight forward. I have an idea for maybe future version of JavaFX (if any JavaFX team members reading, this one’s for you). I don’t know if it would be possible to create like a FXML library. Indeed, I looked the sample apps provided with JavaFX and I saw that the FXML is in the same package as the controller for example, or more generally, there is a package for a functionality. I pretty like this approach, kind of well organizing your architecture. But I usually like to hava same kind of elements in the same place, for example a package for all of my FXML files, another one for my controllers and so on. I really think it is the way you like to organize your code that matters. But anyway, in TweetWallFX a lot of FXML files are there and I said to myself “Well would be great if I had some kind of FXML library”. And I created a really basic one:

public class FXMLLibrary {
  private static final String BASE_PACKAGE = "/com/twasyl/tweetwallfx/fxmls/";
  public static final String TOOLTIP_FXML = BASE_PACKAGE + "tooltip.fxml";
  public static final String TWEETWALLFX_FXML = BASE_PACKAGE + "TweetWallFX.fxml";
  public static final String TWEETBUBBLE_FXML = BASE_PACKAGE + "TweetBubble.fxml";
  public static final String STATISTICS_TAB_FXML = BASE_PACKAGE + "statistics-tab.fxml";
  public static final String STATISTICS_LOOKUP_FXML = BASE_PACKAGE + "statistics-lookup.fxml";
  public static final String WALL_TAB_FXML = BASE_PACKAGE + "wall-tab.fxml";
  public static final String APPLICATION_MENUBAR_FXML = BASE_PACKAGE + "application-menubar.fxml";
  public static final String MUSIC_PLAYER_FXML = BASE_PACKAGE + "music-player.fxml";
  
  public static URL getFXMLUrl(String fxml) {
    return FXMLLibrary.class.getResource(fxml);
  }
}

So if I need to use a particular FXML file in different places, I just need to update the URL in one place if needed. And I am wondering if such a library could be provided by default. I’m coming from the JSF world and in JSF apps you have the faces-config.xml file which contain some context-param, resource bundles and so on. Maybe in JavaFX we could have a jfx-config.xml file with some properties (like resource bundles in JSF) with some maven ideas also, like this:

<jfx-config>
  <properties>
    <base-package>/com/twasyl/tweetwallfx/fxmls</base-package>
  </properties>
  <fxmls>
    <fxml>
      <name>TOOLTIP_FXML</name>
      <url>${base-package}/tooltip.fxml</url>
      <bundle>/com/twasyl/tweetwallfx/resources/i18n/tooltip</bundle>
    </fxml>
    <fxml>
      // ...
    </fxml>
  </fxmls>
</jfx-config>

And the FXMLLoader could be based on the names provided in the config file. I don’t know if this is relevant, I just got the idea. Well that’s it for this article, stay tuned.

Leave a comment