Tải bản đầy đủ
4 Lost in translation? Positioning nodes in the scene graph

4 Lost in translation? Positioning nodes in the scene graph

Tải bản đầy đủ

Bonus: creating hypertext-style links



Bonus: creating hypertext-style links
We ended the last chapter with a bonus example listing, to frame the skills learned in
more of a business/e-commerce context. This chapter’s light synthesizer served as a
fun way to introduce the scene graph, but it has little practical value beyond simply
being entertaining. So before I sum up, let’s indulge in another little detour, by way of
listing 5.5.
Listing 5.5 Link.fx


var border:Number = 20;
var hyperLink:Group = Group {
var t:Text;
var r:Rectangle;
layoutX: border; layoutY: border;
content: [
r = Rectangle {
width: bind t.layoutBounds.width;
height: bind t.layoutBounds.height;
opacity: 0;
onMouseClicked: function(ev:MouseEvent) {
} ,
t = Text {
content: "Link text";
font: Font.font("Helvetica",56);
textOrigin: TextOrigin.TOP;
underline: bind r.hover;
fill: bind if(r.pressed) Color.RED
else Color.BLACK;
Stage {
scene: Scene {
content: hyperLink;
width: hyperLink.layoutBounds.width + border*2;
height: hyperLink.layoutBounds.height + border*2;
resizable: false;

What the listing does is to create a hypertext-like button from some text. Actually,
JavaFX 1.2 came with a link control as standard, but that doesn’t mean we can’t learn
something from crafting our own. Figure 5.14 shows how it looks when running. The




Behind the scene graph

Figure 5.14 The link text depicted in three states: idle (left), underlined when hovered over
(center), and red upon a mouse button press (right)

text is normally displayed black and undecorated, but it becomes underlined when
the mouse is over it. When the mouse button is pressed, the color changes to red,
before returning to black upon release.
The core of the code is in the Rectangle and Text objects used to populate the
scene (via a Group). The Text object is akin to Swing’s JLabel; it’s used to include text
within a scene graph. We’ll cover Text in far more details next chapter, so for now
please forgive me if I gloss over some of its details. The important point to note is that
Text, like other scene graph nodes we encountered this chapter, behaves like a shape,
meaning its concept of area is not limited to merely being rectangular. As the mouse
travels over the text, it constantly enters and leaves the shape, the pointer passing
inside and outside each letter.
Clearly we need the link to behave like a rectangle when it comes to its interaction
with the mouse. To do this we employ an invisible Rectangle behind the Text, taking
responsibility for mouse events. Note how the size of the Rectangle node is bound
tightly to its companion Text node, while the underline decoration and fill color of
the Text node are bound to the Rectangle’s hover state. Also note how the event
function (which runs when the link is clicked) is attached to onMouseClicked() on
the Rectangle, not the Text node.
Now that we have our own handmade hypertext link, we can customize it to our
heart’s content—perhaps make the underline fade in and out, or apply a drop shadow
on mouse over. This was just an example to show how the scene graph sometimes
requires a jot of lateral thinking when it comes to getting the effect you want. In the
next chapter you’ll see further examples of using nodes in clever ways, not just as
proxies for event handling but to add padding around parts of the UI during layout
and to define clipping areas to shape the visibility of a scene graph.


In this chapter we took our first look at the scene graph and played around with
throwing shapes on screen. We saw multiple examples of timeline–based animation
and explored how to define timelines to suit different purposes: triggering events at
given moments and progressively transitioning variables between different states. We
also witnessed how timelines could be used to animate more than just shapes
onscreen. And to cap it all, we dabbled with mouse events.
The LightShow example isn’t the most useful application in the world, and we
didn’t even wire it up to a sound source like true visualizations, but I hope you found




it suitably entertaining. You can use the LightShow application as a framework for
plugging in and trying your own CustomNode experiments, if you wish. There are
plenty of different transformations we didn’t have space to cover in this chapter—you
might want to try playing with some of them, distorting the Rectangle lines or even
adding different shapes of your own and seeing what effects they create.
The bonus listing, I hope, got you thinking about how to adapt the techniques we
used in this chapter for more practical purposes. Indeed in some ways it was a taste of
what’s to come, because in the very next chapter we’ll be staying with the scene graph
but looking at building a slightly more useful application (using video, no less!). We’ll
also be creating our own custom UI components and looking at some of the effects we
can create using the scene graph.
For now, have fun extending and adapting the LightShow, and when you’re ready
I’ll see you in the next chapter!


Moving pictures

This chapter covers

Interacting with complex custom nodes

Laying stuff out on screen, using containers

Playing video

Embedding fonts into an application

In previous chapters we developed an application using JavaFX’s Swing wrappers
and played around with the scene graph. Now it’s time to turn our hands toward
creating a UI that combines the functionality of a traditional desktop application
with the visual pizzazz of the new scene graph library. And when it comes to desktop software, you don’t often get showier than media players.
Some applications demand unique interfaces, games and media players being
prime candidates. They don’t just stick to the conventional form controls but create a less-rigid experience, with sophisticated use of imagery, sound, movement, and
animation. In the chapter 5 we started to explore the JavaFX scene graph, and in
the next chapter we’ll be looking at JavaFX’s standard form controls. So, by way of a
bridge between the two, in this chapter we’ll be getting far more interactive with
the scene graph, by making it respond and animate to a range of mouse events.
The nodes we’ll develop will be far showier (and specialized to the UI experience of



Moving pictures


this project) than the standard controls shipped with JavaFX or Swing. For this reason,
we will be developing them as CustomNode classes, rather than formal Control classes.
(There’s no reason why they couldn’t be written as full-blown controls, but I wanted
this chapter to focus on getting more experience with the scene graph.)
We’ll also look at using the media classes to play videos from the local hard disk. To
try out the project (see figure 6.1) you’ll need a directory of movie files, such as MPEG
and WMV files.
The video player we’ll be developing is very primitive, lacking much of the functionality of full-size professional players like Windows Media Player or QuickTime. A
full player application would have been 10 times the size with little extra educational
value. Although primitive in function, our player will require a couple of custom controls, each demonstrating a different technique or skill.
We’ll also be adding a gradient fill to the background, and a real-time reflection
effect will be applied to the video itself, making it look like it’s resting on a shiny surface.

This project requires a few images, which can be downloaded along with
the source code from the book’s website: http://www.manning.com/

Moving pictures

Over the coming pages you’ll learn about working with images and video, creating
controls from scene graph shapes, and applying fancy color fills and effect. This is
quite a busy project, with a lot of interesting ground to cover, so let’s get started.

Figure 6.1

A preview of the simple video player we’ll be building in this chapter





Moving pictures

Taking control: Video Player, version 1
In this version of the player software we’re focusing mainly on building the UI we’ll
need when we manipulate our video later on. Before JavaFX came along, getting video
to work under Java would have deserved an entire book in itself. Thankfully, JavaFX
makes things a lot easier. JavaFX’s video classes are easy to use, so we don’t have to
devote the entire chapter to just getting video on screen.
You can see what this stage of the project looks like in figure 6.2.

Figure 6.2
The interface for version 1
of our application

We’ll begin simply enough, with the control panel that sits at the foot of the video
player. It includes two examples of custom UI classes. The first is an image button,
demonstrated to the left in figure 6.2; the second is a layout node, positioning the sliders and text to the right in figure 6.2.
We’ll tackle the button first.


The Util class: creating image nodes
As before, the code is broken up into several classes and source files. But before we
look at the button class itself, we’ll take a short detour to consider a utility class. Quite
often when we build software, the same jobs seem to keep coming up time and again,
and sometimes it’s useful to write small utility functions that can be called on by other
parts of the code.
In our case the button we’re writing needs to load images from a directory associated with the program—these are not images the user would choose but icons that
come bundled with our player application. The code is shown in listing 6.1.
Listing 6.1 Util.fx
package jfxia.chapter6;
import javafx.scene.image.Image;
import java.io.File;
import java.net.URL;
package function appImage(f:String) : Image {
Image {
url: (new URL("{__DIR__}../../images/{f}")).toString();

The script-level (static) function appImage() is used to load an application image from
the project’s images directory, such as icons, backgrounds, and other paraphernalia that


Taking control: Video Player, version 1


might constitute our UI. It accepts a string—the filename of the image to load—and
returns a JavaFX Image class representing that image. The JavaFX Image class uses a URL
as its source parameter, explaining the presence of the Java URL class. Have you noticed
that strange symbol in the middle of the code: __DIR__? What does it do?
It’s an example of a predefined variable for passing environment information into
our running program.

__DIR__ returns the location of the current class file as a URL. It may point to a
directory if the class is a .class bytecode file on the computer’s hard disk, or it
may point to a JAR file if the class has been packaged inside a Java archive.
__FILE__ returns the full filename and path of the current class file as a URL.
__PROFILE__ returns either browser, desktop, or mobile, depending on the
environment the JavaFX application is running in.

Note how both __FILE__ and __DIR__ are URLs instead of files. If the executing class
lives on a local drive, the URL will use the file: protocol. If the class was loaded from
across the internet, it may take the form of an http:-based address.
Most of you should have realized the appImage() function isn’t the most robust
piece of code in the world. It relies on the fact that our classes live in a package called
jfxia.chapter6, which resolves to two directories deep from the application’s root
directory. It backs out of those directories and looks for an images directory living
directly off the application root. If we were to package the whole application into a
JAR, this brittle assumption would break. But for now it’s enough to get us going.


The Button class: scene graph images and user input
The Button class creates a simple push button of the type we saw in our Swing example
in chapter 4. However, this one is built entirely using the scene graph and has a bit of
animation magic when it’s pressed. The Button is a very simple component, which offers
an ideal introduction to creating sophisticated, interactive, custom nodes.
The button is constructed from two bitmap graphics: a background frame and a
foreground icon. When the mouse moves over the button its color changes, and when
clicked it changes again, requiring three versions of the background image: the idle
mode image, the hover image, and the pressed (clicked)
image. See figure 6.3.
When the button is pressed, the copy of the icon
expands and fades, creating a pleasing ghosted zoom
animation. Figure 6.3 demonstrates the effect: the
arrow icon animates over the blue circle background.
We’ll be constructing the button from scratch, using a
CustomNode, and implementing its animation as well as
Figure 6.3 The button is
constructed from two bitmap
providing our own event handlers (because a button
images: a background (blue
that stays mute when pressed is about as much use as
circle) and icon (arrow). When
the proverbial chocolate teapot).
the button is pressed, a ghost
of its icon expands and fades.
Enough theory. Let’s look at the code in listing 6.2.