FX Experience Has Gone Read-Only

I've been maintaining FX Experience for a really long time now, and I love hearing from people who enjoy my weekly links roundup. One thing I've noticed recently is that maintaining two sites (FX Experience and JonathanGiles.net) takes more time than ideal, and splits the audience up. Therefore, FX Experience will become read-only for new blog posts, but weekly posts will continue to be published on JonathanGiles.net. If you follow @FXExperience on Twitter, I suggest you also follow @JonathanGiles. This is not the end - just a consolidation of my online presence to make my life a little easier!

tl;dr: Follow me on Twitter and check for the latest news on JonathanGiles.net.

Text “Alignment” Trick

One of the annoying sharp edges in JavaFX is around text alignment, especially with regards to the Text node. In this tip, I’m going to skip using the Text node in favor of using the Label control, because it gives you better… uh… control over text placement. This is actually based on a trick I used to use with Swing all the time. If I wanted to center some text in a layout, I’d specify the space I wanted the text positioned within by setting the size of the label to match that space, and then I’d either position the text at the center, top, right, etc.

Using the same trick in JavaFX, I can cause some text to be right positioned. An additional benefit to using the Label control is that if the space isn’t big enough for the text, it can be elided using the textOverrun variable.

    Label {
        width: bind 120
        text: "Right Positioned Message!"
        font: Font { size: 10 }
        textFill: Color.BLACK
        hpos: HPos.RIGHT
    }

Anyway, it ain’t perfect but a good trick for the moment.

How To Embed Fonts

How To Embed Fonts

I was going through my bug list today and noticed this bug, Document how to embed fonts in FX apps. A quick google search turned up a single forum posting on the subject which just linked back to the root bug (lucky for me I put the solution in the bug report so people weren’t completely stuck). Surprisingly, I couldn’t find any documentation on the subject here at FXExperience.com, so I thought to rectify that with a short post explaining the subject. (more…)

Dynamic Cell Sizes

One of the really neat things about the JavaFX ListView control is the Cell API, and the ability to have dynamically variable row heights, without sacrificing performance or scalability. To accomplish this, we’ll write a custom Cell factory which will create a Cell who’s size depends on some state.

To recap briefly, to remain scalable and fast, the ListView reuses Cells for rendering each row in the ListView. Because it reuses Cells, each Cell needs to be designed so that it does the right thing no matter what row it is asked to represent — even empty rows which are used only for filling out a ListView and not for actually holding valid data. (more…)

Creating a partially rounded rectangle

After seeing a twitter message today asking whether it was possible to create a rectangle in JavaFX which was a mixed rounded and normal rectangle, I thought I’d post how I did this a few months back.

The code below will draw a rounded rectangle in the top-right, bottom-right, and bottom-left corners. The top-left corner is a square point. You can change this by editing the four parameters, and of course trivially modify this code to be a function taking four arguments.

The reason why I have the test for if (topRightCurve > 0) is because when I was writing this code there was a known issue with drawing arcs with a zero radius. I know this has been fixed, but I’m not sure when it was fixed (it may be in 1.2, but most certainly it’s fixed in 1.3).

[jfx]
public var topLeftCurve:Number = 0;
public var topRightCurve:Number = 0;
public var bottomLeftCurve:Number = 0;
public var bottomRightCurve:Number = 0;

Path {
fill: color
stroke: stroke
strokeWidth: 1
elements: bind [
// starting just past the top-left curve
MoveTo { x:topLeftCurve, y:0 },

// draw line to where top-right curve should start
HLineTo { x:menuWidth – topRightCurve },

// arc around to just below the top-right curve
if (topRightCurve > 0) {
ArcTo {
x:menuWidth, y:topRightCurve,
radiusX:topRightCurve, radiusY:topRightCurve,
sweepFlag:true
}
} else null,

// go to just above the bottom-right curve
VLineTo { y: menuHeight – bottomRightCurve }

// arc around to just to the left of the bottom-right curve
if (bottomRightCurve > 0) {
ArcTo {
x:menuWidth-bottomRightCurve, y:menuHeight,
radiusX:bottomRightCurve, radiusY:bottomRightCurve,
sweepFlag:true
}
} else null,

// draw line to where bottom-left curve should start
HLineTo { x:bottomLeftCurve },

// arc around to just above the bottom-left curve
if (bottomLeftCurve > 0) {
ArcTo {
x:0, y:menuHeight-bottomLeftCurve,
radiusX:bottomLeftCurve, radiusY:bottomLeftCurve,
sweepFlag:true
}
} else null,

// go to just below the top-left curve
VLineTo { y: topLeftCurve }

// arc around to just above the bottom-left curve
if (topLeftCurve > 0) {
ArcTo {
x:topLeftCurve, y:0,
radiusX:topLeftCurve, radiusY:topLeftCurve,
sweepFlag:true
}
} else null
]
}
[/jfx]

Also, if you’re using the JFXtras project, there is a shape in there, called the MultiRoundRectangle that does precisely this as well.

Text Transitions

While pouring over bug reports today I ran across an older one, RT-4829. Essentially what the bug submitter wanted was the ability to animate text in a Text node or label. So it starts out with no characters and then a character at a time is added to the node. The sample code posted in the bug report was pretty cool, it looked a lot like one of the text bubbles you’d see in Dragon Warrior or some other old school RPG. It occurred to me that this is fertile ground for an aspiring JavaFX library developer 🙂

[jfx]
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.effect.DropShadow;
import javafx.scene.text.Text;
import javafx.scene.text.TextOrigin;
import javafx.scene.text.Font;
import javafx.scene.shape.Rectangle;
import javafx.scene.paint.Color;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;

def BASE_WIDTH = 800;
def BASE_HEIGHT = 600;
def MARGIN = 20;

var backgroundRect = Rectangle
{
x: 0
y: 0
width: BASE_WIDTH
height: BASE_HEIGHT

onMouseClicked: function(event) { t.playFromStart() }
}

var boundingRect = Rectangle
{
x: MARGIN * 2
y: BASE_HEIGHT * 2 / 3 – MARGIN
width: BASE_WIDTH – MARGIN * 4
height: BASE_HEIGHT – (BASE_HEIGHT * 2 / 3)
fill: Color.rgb(255, 255, 255, 0.2)
stroke: Color.WHITE
strokeWidth: 2
}

var displayedText = Text
{
x: boundingRect.x + MARGIN
y: boundingRect.y + MARGIN
wrappingWidth: boundingRect.width – MARGIN * 2
content: ""
font: Font { size: 36 }
textOrigin: TextOrigin.TOP
//stroke: Color.BLACK
fill: Color.WHITE
effect: DropShadow {}
}

def FINAL_TEXT = "I was trying to get the text to wrap, but the text layout engine would keep putting a character on the previous line until the full word was visible.";
var charCount = 0 on replace
{
var textToDisplay = FINAL_TEXT.substring(0, charCount);
displayedText.content = textToDisplay;
}

Stage
{
title: "Text demo"
visible: true
scene: Scene
{
width: BASE_WIDTH
height: BASE_HEIGHT
fill: Color.BLACK
content:
[
backgroundRect,
boundingRect,
displayedText
]
}
}

var t = Timeline
{
keyFrames:
[
// In reality the speed would be per letter so the times would
// be computed dynamically. I have an idea of how to do that.
// Initial experiments also suggest that the speed of displaying
// each letter should be relative to the width of the letter.
KeyFrame { time: 0s, values: charCount => 0 }
KeyFrame { time: 3s, values: charCount => FINAL_TEXT.length() }
]
};
t.play();
[/jfx]

I think the actual feature the developer was asking for (the ability to say, KeyFrame { time: 3s, values: text => “This is the text to transition to” }) wasn’t the right way to go about the problem. Rather, there should be a handful of Transition class implementations for handling special text transition effects. So that you would be able to write something like:

[jfx]
def transition = TypewriterTextTransition {
rate: .5s
node: someTextNodeOrLabelOrSomething
toValue: "This is the text I’d like to transition to"
}
[/jfx]

And then you start the transition and voilà! It encapsulates all the nasty details and provides useful knobs for various types of effects you may want (for example, in addition to just having the letters appear, you could fade them in one at a time or have them drop from the sky or whatever you want).

Seems like a cool project for somebody who wants to get into learning JavaFX!