Controlling Media Playback
This article discusses creating a full-functional media player with graphical UI elements that control the media playback.
Figure 1: Media Player With Custom Controls
Both control panel and graphical elements are encoded by using the JavaFX Script programming language. For your media player, you can follow the same approach, or pre-render graphical controls as bitmaps in Adobe Photoshop.
To create a media player you need to implement the structure of the three nested media objects, encode graphical controls, and add some logic for playback functions.
Figure 2: Structure of a Media Player With Custom Controls
Embedding Media Into the Web Page explains in detail how to create a JavaFX media player and integrate it into the application's scene, but this article focuses mainly on creating control elements. In this application, the media control panel consists of three elements: playButton, progress, and volumeControl, as shown in the following figure.
Figure 3: Media Control Panel
Creating Controls
- To construct the
playButtoncontrol, draw three graphical elements:circle,playShape,pauseShape.
circleA substrate element with an applied animated effect. playShapeA control to process the pause action. pauseShapeA control to process the play action.
Refer to the PlayButton.fx file for implementation details. - Add a pulsing effect to
circleto visually enhance that element.
var boomTimeline:Timeline = Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at(0ms) {
offset => 0.9
},
at(500ms) {
offset => 0.7 tween Interpolator.EASEBOTH
}
]
}
-
The
- Construct the
progresscontrol by drawing the following graphical elements:frame,bar,progressBar,button,status, andballoonLabel.

frame A substrate element. bar An element to handle a cursor style change. progressBar A bar to visualize the current position playback timeline. button A slider's knob to visualize a proportion of the elapsed to the remaining playback time. Can be dragged to enable playing the particular media fragment. status A text field to display the elapsed and the remaining playback time. ballonLabel An element to display the current media time when the button element is being dragged.
Refer to the Slider.fx and theTextBalloon.fxfiles for implementation details. - Draw the
volumeControlelement that consists of a speaker icon and of a vertical slider.

speaker A control element with an applied animated effect to enable the mute and unmute function. slider A vertical version of the slider element to alter the volume level of the media. The element becomes visible when the speaker control is hovered over.
Refer to the VolumeControl.fx, Slider.fx and SpeakerIcon.fx files for implementation details. - Add a live effect to the speaker control. The following animation construction visualizes and hides, in turn, arc elements in blue and white to produce an effect of radio waves being emitted from a live radio speaker.
boomTimeline animation construction in the PlayButton.fx file alters the offset variable, thus varying the offset of the radial gradient fill for the circle element. The animation is launched in the makeInitUI() function when the application starts, which produces an effect of perpetually pulsing button.
var t: Timeline = Timeline {
repeatCount: -1
keyFrames: [
KeyFrame {
time: 0s
action: function() {
arc1.visible = false;
arc2.visible = false;
}
},
KeyFrame {
time: 500ms
action: function() {
arc1.visible = true;
arc2.visible = false;
}
},
KeyFrame {
time: 1000ms
action: function() {
arc1.visible = true;
arc2.visible = true;
}
},
KeyFrame {
time: 1500ms
action: function() {
arc1.visible = false;
arc2.visible = false;
arc1.stroke = if(arc1.stroke == Color.BLUE) Color.WHITE else Color.BLUE;
arc2.stroke = if(arc2.stroke == Color.BLUE) Color.WHITE else Color.BLUE;
}
}
]
}
- Add the created graphical elements to the media control panel. In this example, the
BottomControllerobject is aCustomNodeextension. It sets values for all public variables of control elements and adds the variables to the panel's content.
public class BottomController extends CustomNode {
...
//Sets the public variables of the control elements
override function create(): Node {
Group {
content: [
playButton,
progress,
volumeControl,
]
}
}
}
Adding Functional Logic
After all the controls have been created and added to the control panel, add functional logic to manage the media playback and make your application interactive.
- To enable your graphical elements to process the mouse events, add the corresponding event-handling functions to your code.
Control Function Action playShapeonMouseClicked
Enables media playback and sets the "pause" view for the play/pause button.
See thePlayButton.fxfile.pauseShapeonMouseClicked
Disables media playback and sets the "play" view for the play/pause button.
See thePlayButton.fxfile.baronMouseClicked
Defines the progress bar position for vertical and horizontal sliders.
See theSlider.fxfile.onMouseEntered
Sets the hand cursor style.
See theSlider.fxfile.onMouseExited
Sets the default cursor style.
See theSlider.fxfile.buttononMouseDragged
Defines the position for the dragged knob and passes it to the media player.
See theSlider.fxfile.onMouseEntered
Enables showing the ballonLabelelement.
See theSlider.fxfile.onMouseDragged
Disables media playback and sets the "play" view for the play/pause button.
See theSlider.fxfile.slideronMouseEntered
Keeps the volume slider visible.
See theVolumeControl.fxfile.onMouseExited
Hides the volume slider.
See theVolumeControl.fxfile.speakeronMouseEntered
Enables showing the volume slider.
See theVolumeControl.fxfile.onMouseExited
Hides the volume slider.
See theVolumeControl.fxfile.onMouseClicked
Mute and unmute the audio output.
See theVolumeControl.fxfile. - Invoke playback control functions for the media player object,
myPlayer.
Volume and Mute
The following code fragment in the BottomController file binds the volume level and the mute status retrieved from the control elements to the corresponding variables of the myPlayer object.
var volumeControl = VolumeControl {
x: bind width-30
y: bind (height-20)/2.0 + 20
volume: bind myPlayer.volume with inverse
mute: bind myPlayer.mute with inverse
...
}
Current Time
The current position of the progress bar slider is bound to the current time of the playback through the progress variable of myPlayer. The following code fragment from the BottomController file binds the slider's value to the progress variable.
var progress: Slider = Slider {
orientation: Slider.HORIZONTAL
x: bind playButton.centerX+playButton.radius+30
y: bind (height-ProgressSlider_height)/2.0
width: bind width-(progress.x+80)
value: bind myPlayer.progress with inverse;
}
The progress is taken into account when the currentTime variable is calculated. See the myPlayer file.
public var progress: Number = 0 on replace {
if(media != null) {
if(media.duration.toMillis() != java.lang.Double.NEGATIVE_INFINITY and
media.duration.toMillis() != java.lang.Double.POSITIVE_INFINITY) {
skip = true;
currentTime = media.duration.mul(progress);
skip = false;
}
}
}
Play and Pause
The play and pause actions fired by clicking the playButton element are bound to the BottomController functions of the same name. See the BottomController file.
public var playButton = PlayButton {
...
playAction: bind playAction
pauseAction: bind pauseAction
These functions invoke correspondingly the play() and pause() functions of the myPlayer object.
var bottomController:BottomController = BottomController {
playAction: function() {
if(myPlayer.media != null) {
...
myPlayer.play();
...
}
}
pauseAction: function() {
...
myPlayer.pause();
}
}
Press the Launch Application button at the top of the page to run the sample by using Java Web Start software. Download the NetBeans project and explore other capabilities of the JavaFX media functionality provided in this application.
In order to play the media content used in this application, ensure that the required codecs are installed in your system.
Sandeep Konchady
Staff Engineer, Sun Microsystems
Alla Redko
Technical Writer, Sun Microsystems