Module 1 Task 3: Adding an Expansion Effect
- Highlights
-
- Use
javafx.scene.Groupandjavafx.scene.shape.Rectangleto enable thumbnails to be positioned collectively - Use
preserveRatioto preserve the original aspect ratio when scaling an image - Use
onMouseEnter()andonMouseExit()to trigger scaling
- Use
Introduction
This task scales all thumbnails proportionately and adds a mouseover effect to individual thumbnails. As shown in Figure 1, the thumbnail beneath the cursor is 25% larger:
Figure 1
Adding the expansion effect on the thumbnails presents two challenges.
- Centering the thumbnail after it has been scaled to fit the fitWidth and fitHeight constraints
- Handling the expansion such that it doesn't cause the wall to resize (resizing causes the wall to be recentered, which causes the wall to "jump").
Running the Project
- Download the Module 1 Task 3 NetBeans project.
- Run the project.
In Module 1 Task 2 all the thumbnails were the same size. In Task 3 the thumbnails are sized proportionately. - Run the cursor across the wall. As the mouse passes over a thumbnail it is enlarged. As the mouse exits it shrinks to normal size.
Architecture
Because you are only adding an additional mouse behavior, you add new functions to Thumbnail.fx and edit Wall.fx. As seen in Figure 2, there are no new files in the project.
Figure 2
Creating a Group of Thumbnails
In Thumbnail.fx, you size the image to fit the
thumbnail's dimensions while preserving the image ratio. The expansion
effect scales the thumbnail, enlarging it by 25 percent as the mouse
passes over, and scaling it to 100 percent on exit.
In the previous task the height of the wall was the height of the thumbnails (THUMB_HEIGHT) plus the THUMB_VERTICAL_SPACING
between thumbnail rows and between thumbnails and the frame. Now the
expansion effect causes the overall size of the wall to change when a
thumbnail in the top or bottom row is expanded. If the expansion is not
taken into account, the wall will appear to jump around as it resizes.
In this task the problem is already solved, but taking a step back in the development process is a good way to understand both the problem and the solution. Follow these steps:
- Edit
Thumbnail.fx. - Use // to comment out passages that refer to Rectangle:
- Lines 119-123:
def boundingRect = Rectangle { ... } - Lines 133 and 134:
translateX: bind ... and translateY: bind ... - Line 172:
boundingRect
- Lines 119-123:
- Run the project.
- Mouse over thumbnails in the top or bottom rows. As you mouse over
images the wall "jumps".
Compare Figure 3 below to Figure 1. Note how both the landscape images
on the bottom are shifted to the right instead of being centered in the
column.
Figure 3
- Remove the comments you made in Step 2.
Create a Bounding Rectangle
Because you determine the wall dimensions based on the thumbnail
dimensions, you need to accommodate the expansion effect. As defined
below, the rectangle is a container for the thumbnail. Multiplying by EXPANDED_THUMB_SCALE ensures the wall size will be correct, and eliminates the "jumping" you saw earlier.
def boundingRect = Rectangle {
width: Constants.THUMB_WIDTH * Constants.EXPANDED_THUMB_SCALE
height: Constants.THUMB_HEIGHT * Constants.EXPANDED_THUMB_SCALE
visible : false
}
Seeing the outline of the boundingRect (or any other invisible rectangle) can be a useful debugging tool. By initializing boundingRect's fill and stroke, and setting visible to true, the outline can be seen:
fill : null
stroke : javafx.scene.paint.Color.YELLOW
visible : true
Sizing the Thumbnail and Preserving Aspect Ratio
Now that the rectangle contains the thumbnail you need to size the thumbnail so that its aspect ratio is maintained, then center the thumbnail within the rectangle:
translateX: bind (boundingRect.boundsInLocal.width
- imageView.width) / 2.0
translateY: bind (boundingRect.boundsInLocal.height
-imageView.height) / 2.0
fitWidth: Constants.THUMB_WIDTH
fitHeight: Constants.THUMB_HEIGHT
preserveRatio: true
Scaling With onMouseEntered and onMouseExited
Thumbnail.fx contains the new onMouseEntered and onMouseExited functions. These functions inherit scaleX and scaleY from javafx.scene.Node, so scaling is done from the center of the object. This is why the boundsInLocal values (used to calculate size) are important.
onMouseEntered: function(evt: MouseEvent) : Void {
imageView.scaleX = Constants.EXPANDED_THUMB_SCALE;
imageView.scaleY = Constants.EXPANDED_THUMB_SCALE;
}
// Scale the thumbnail back down for normal display when the mouse exits.
onMouseExited: function(evt: MouseEvent) : Void {
imageView.scaleX = 1;
imageView.scaleY = 1;
Note that scaling applies to the imageView only (not the Rectangle you see in the code, or the Thumbnail CustomNode).
Creating a Group
Thumbnail.fx uses a Group in the create()
function. Note the reflection effect, which was inside ImageView in
Task 2, is now in effect before the group's content is formed. A Group
is a node in the scene-graph that has a multiplicity of children. Nodes
in a Group can be handled as a single Node. In the following code, the
Rectangle is one Node in the Group and imageView is another. The reflection applies to the Group, so any Node in the Group has the reflection effect
Group {
effect: if (reflect) then reflection else null;
content: [
boundingRect,
imageView
]
}
Try It
- In
Photo.fx, experiment with changing the look and feel.
- Change the value of gap and observe how this affects the spacing throughout.
- Change the frame attributes.
- Move the reflection effect to
imageView. What changes need to be made to theboundingRect? (Hint: How does the reflection affect the height of theimageView?)
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.
