Module 1 Task 2: Creating a Wall of Thumbnails
- Highlights
-
- Work with a Sequence to retrieve metadata from a URL
- Use bound variables
- Create a loose binding between script modules
- Use metadata to position images in a resizable grid using
xoffset(),translateX, andtranslateY - Create a reflection effect on a thumbnail
Introduction
In Task 1 the application uses a single media file to create a thumbnail. The thumbnail is centered on a stage. Clicking the thumbnail displays a scaled-up version of the image and its file name (the only available metadata thus far). A second click hides the larger image.
In Task 2 you gather file metadata and use it to lay out thumbnails in a grid (a wall with three rows and many columns). The onMouseClicked
behavior is the same as Task 1, except now the application centers the
wall within a resizeable window, and centers the scaled-up thumbnail
over the wall.
Running the Project
- Download the Module 1 Task 2 NetBeans project.
- Run the project. The wall is displayed as shown in Figure 1.
- Click a thumbnail to see the full size view with the file name.
- Click the full scale view to close the enlargement.
- Resize the window to see how the application adjusts. Note, you will create a scroll control in a future module.
Figure 1
Architecture
Task 1 lays the groundwork for image handling. You start with the CustomNodes Thumbnail.fx, Photo.fx, and Main.fx, and the class Constants.fx.
As shown in Figure 2, Task 2 adds a new class, MetaData.fx, and a new CustomNode, Wall.fx.
The following diagram shows new or changed portions in blue, and lists
some major differences. If you diff Task 1 and Task 2 source files you
can see that using metadata affects all classes.

Figure 2
Using the MetaData Class to Size and Position Thumbnails
MetaData (in MetaData.fx) creates a data model. This section reviews how MetaData is used throughout this task.
Creating a Data Model
Take a look at the new MetaData.fx CustomNode. MetaData is a container that stores the thumbnail URL, the media URL, and the file name in one place.
package class MetaData {
package var thumb_url : String;
package var media_url : String;
package var filename : String;
}
In Task 2 the media URL and the thumbnail URL have the same value, but the values can be different. The variable sampleMetaData is a Sequence of 60 MetaData objects, and Main.fx eventually references it to populate the wall. This test data will be replaced with web data in future tasks.
Using MetaData in Thumbnail.fx
Thumbnail is a CustomNode that encapsulates the MetaData and corresponding thumbnail image. To support metadata, references to the url variable have become references to the metaData variable.
In Thumbnail, the image variable is initialized with metaData.thumb_url. The PHOTO_PLACEHOLDER is displayed while the image is being loaded in the background.
def image : Image = Image {
url: metaData.thumb_url
backgroundLoading: true
placeholder: placeholder
}
Using MetaData in Photo.fx
As seen in Module 1 Task 1 the Photo.fx CustomNode defines the ImageView variable to contain the full image. The ImageView variable is defined to be javafx.scene.image.ImageView. Image sizing and other image display actions operate on the ImageView container. Photo.fx
also positions the filename metadata in relation to the image, puts a
border around the image, and specifies a placeholder for the image.
Photo.fx makes the following small changes:
- Declarations that used the "canned" URL in Task 1 now get the URL from the
MetaDataobject. - Creates a new variable named
metaData, wheremetaDatais an object of typeMetaData, as defined inMetaData.fx.
Note that the Photo.fx image definition is very similar to the definition in Thumbnail.fx. In Photo.fx the image URL is metaData.media_url, and in Thumbnail.fx the image URL is metaData.thumb_url.
Creating a Reflection Effect
Thumbnail.fx manages the thumbnail appearance so the
reflection effect is defined here. The effect is applied when the
Thumbnail is in the bottom row of the wall, as determined by Wall.fx. The reflect variable is a way for Wall.fx to tell the Thumbnail to apply the reflection effect.
Thumbnail imports classes javafx.scene.effect, the package that supports effects. The new variable reflect is used to apply the reflection
to the Thumbnail. Effects can be applied to any Node and in this case
the reflection is applied to the Thumbnail as a whole. The following
passage defines the reflection settings.
def reflection : Effect = Reflection {
fraction: .6
topOpacity: .6
bottomOpacity: 0
topOffset: 3
}
Note that reflection is not part of the Thumbnail class. reflection is a script-level variable because the values never change. The effect is initialized in the create() function such that the reflection only appears when reflect is true.
effect: if ( reflect ) then reflection else null
Loading and Displaying Many Thumbnails
This section discusses the new class Wall.fx and how Main.fx uses metadata to push thumbnails onto the Wall.
Creating and Positioning Thumbnail Instances
Wall.fx is a CustomNode that is the container for the grid of thumbnails. It collects metadata and creates the variable thumbnails to hold images for the wall. Wall then uses x and y coordinate translation to lay out the wall. Open Wall.fx and take a few minutes to read the comments. Wall is created in Main.
As new data arrives, it pushes metadata into the MetaData object and the images load onto the wall. Wall contains a sequence of metaData. The metaData sequence has a visual representation in the thumbnails that appear in the Wall. The metaData sequence is initialized in Main to be a sequence of sample data. Later, the metadata will come from a web search API.
package var metaData : MetaData[]
Take a look at the variable fullView - it's a variable that is a function:
package var fullView : function(metaData : MetaData, placeholder : Image) : Void;
fullView is called when the user clicks on a thumbnail.
This function allows Thumbnail to be totally ignorant of how the full
view of the thumbnail gets displayed. This is a good design goal since
you can change Photo without worrying about what's going on in
Thumbnail.
Note: The fullView implementation is in Main.fx, but since thumbnails are created in Wall.fx, the fullView variable must be initialized as shown above. In practice, when Main creates wall, it initializes Wall's fullView variable and Wall uses that to initialize Thumbnail. This "cross referencing" can be avoided if you move fullView out of Main and into Wall.
The following code positions the thumbnail.
translateX: (col * Constants.THUMB_WIDTH) +
(col * Constants.THUMB_HORIZONTAL_SPACING)
translateY: (row * Constants.THUMB_HEIGHT) +
(row * Constants.THUMB_VERTICAL_SPACING)
Bringing It All Together in Main.fx
Main.fx already handles user interaction with a thumbnail. In this task the application does the following:
- References
MetaDatarather than a URL - Adds the wall to the stage, placing it in the center
- Uses
MetaDatato populate the wall with images
Main.fx is well commented, so take some time to read the comments and examine the code.
Note how the javafx.scene.Node variable boundsInLocal
is used to position the photo on the wall, and the wall on the scene.
In this application width and height are the only important factors,
and they are going to be the same in the parent, the scene and the
screen. Using boundsInLocal avoids the additional overhead of computing boundsInParent, boundsInScene, or boundsInScreen. If it is necessary to use x and y coordinates, you might need to use one of the other boundsIn* variables.
Try It
- In
Constants.fx, try changingTHUMB_WIDTH,THUMB_HEIGHT,THUMB_VERTICAL_SPACING, andTHUMB_HORIZONTAL_SPACING. Run the project to see the result. - In
Thumbnail.fxsetbackgroundLoadingto false. Run the project and note the behavior change. SetbackgroundLoadingto true once you are done. - Try editing
Constants.fxto change the value ofTHUMB_ROWS, and run the project. You might have to resize the window to view your results. - Try changing the reflection settings mentioned in Creating a Reflection Effect and run the project to see the results.
- Try some of the other effects in the
javafx.scene.effectspackage. Note that many of the effects can use other effects as input, so try combining more than one effect.
We welcome your participation in our community. Please keep your comments civil and on point. You may optionally provide your email address to be notified of repliesyour information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use.
