Script Part9 PDF

Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

46 Advanced Java for Bioinformatics, WS’17/18, D.

Huson, December 21, 2017

11 FXML and CSS

A program intended for interactive use may provide a large number of user interface (UI) components,
as shown here:

The UI shown above is implemented using Java Swing and all the menu items, buttons, labels, tree
views etc. are implemented in procedual code; all items are created, layouted and have functionality
associated with them using Java code.
The perferred way to build a UI in the context of JavaFX is not to use to procedual code but rather
to specify the UI using FXML.
FXML features1 :

• it is a scriptable, XML-based markup language


• allows one to construct Java object graphs
• provides an alternative to using procedural code
• is ideally suited for defining the UI of a JavaFX program because the hierarchial structure of an
XML document mirrors the structure of a scene graph.

11.1 FXML
FXML provides elements for representing:
• class instances
• properties of class instances
• “static properties”
• “define blocks“
• scriptable code
In the following we discuss some of the main features of FXML, with the goal of getting a basic
understanding of how FXML operates.
We will be using an interactive tool called SceneBuilder to create FXML files.
1
This chapter is based on: Introducing FXML - A Markup Language for JavaFX, Greg Brown, 8/15/2011, http:
//fxexperience.com/wp-content/uploads/2011/08/Introducing-FXML.pdf
Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017 47

11.1.1 Creating class instances


Class instances can be constructed in FXML in several ways:

• instance declaration by name

• referencing or copying existing instances, e.g. from included external FXML files

For example, a Label object with the text “Hello World!” can be constructed as follows:
<j a v a f x . s c e n e . c o n t r o l . L a b e l t e x t=” H e l l o , World ! ”/>

or
<?import j a v a f x . s c e n e . c o n t r o l . L a b e l?>
<L a b e l t e x t=” H e l l o , World ! ”/>

FXML supports more advanced constructs as well. For example, if you want to setup a HashMap and
provide some entries, then that can be done as follows:
<HashMap peptideA=”AVVLPVLVAVAC” peptideB=”GGGHGHGEEGEC”/>

This will create a map with two key-value pairs: (peptideA,AVVLPVLVAVAC) and
(peptideB,GGGHGHGEEGEC).
Classes that provide a valueOf() method can be inialized as shown in these examples:
<S t r i n g f x : v a l u e=” H e l l o , World ! ”/>
<Double f x : v a l u e=” 1 . 0 ”/>
<Boolean f x : v a l u e=” f a l s e ”/>

FXML supports the use of “factories” and “builders” to setup instances of classes. For example, the
following produces a color object:
<C o l o r r e d=” 1 . 0 ” g r e e n=” 0 . 0 ” b l u e=” 0 . 0 ”/>

11.1.2 Properties
If an element represents a property setter, the contents of the element (which must be either a text
node or a nested class instance element) are passed as the value to the setter for the property, like
this:
<?import j a v a f x . s c e n e . c o n t r o l . L a b e l?>
<Label>
<t e x t >H e l l o , World! </ t e x t >
</Label>

This has the same effect as the construct reported above:


<?import j a v a f x . s c e n e . c o n t r o l . L a b e l?>
<L a b e l t e x t=” H e l l o , World ! ”/>

FXML uses “type coercion” to convert property values to the appropriate type as needed.
This is required because XML only supports elements, text and attributes with text values.
However, Java supports a number of different data types including built- in primitive value types as
well as extensible reference types.
For example, based on type coercion, this works as intended:
<R e c t a n g l e x=” 10 ” y=” 10 ” width=” 320 ” h e i g h t=” 240 ”
f i l l =”#f f 0 0 0 0 ”/>

The result is a Rectangle object with the given dimensions and fill color.
FXML provides a mechanism for adding elements to a list, for example, this adds children to a group:
48 Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017

<Group>
<c h i l d r e n >
<R e c t a n g l e f x : i d=” r e c t a n g l e ” x=” 10 ” y=” 10 ” width=” 320 ”
h e i g h t=” 240 ” f i l l =”#f f 0 0 0 0 ”/>
...
</ c h i l d r e n >
</Group>

11.1.3 Static properties


Static properties are usually defined by some other class (often, the parent container of a control).
For example, when using a grid pane in procedural code, you may want to do something like this:
GridPane g r i d P a n e = new GridPane ( ) ;
L a b e l l a b e l = new L a b e l ( ) ;
l a b e l . s e t T e x t ( ”My L a b e l ” ) ;
GridPane . setRowIndex ( label , 0 ) ;
GridPane . setColumnIndex ( label , 0 ) ;
g r i d P a n e . g e t C h i l d r e n ( ) . add ( l a b e l ) ;

This can be expressed like this in FXML:


<GridPane>
<c h i l d r e n >
<L a b e l t e x t=”My L a b e l ”>
<GridPane . rowIndex >0</GridPane . rowIndex>
<GridPane . columnIndex >0</GridPane . columnIndex>
</Label>
</ c h i l d r e n >
</GridPane>

11.1.4 Define blocks


FXML allows one to create objects that exist outside of the object hierarchy and need to be referred
to.
For example, recall that a ToggleGroup object is required to link a set of radio buttons. This shows
how to do this:
<VBox>
<f x : d e f i n e >
<ToggleGroup f x : i d=” myToggleGroup ”/>
</ f x : d e f i n e >
<c h i l d r e n >
<RadioButton t e x t=”A” t o g g l e G r o u p=” $myToggleGroup ”/>
<RadioButton t e x t=”B” t o g g l e G r o u p=” $myToggleGroup ”/>
<RadioButton t e x t=”C” t o g g l e G r o u p=” $myToggleGroup ”/>
</ c h i l d r e n >
</VBox>

11.1.5 Referencing elements


How to reference the toggle group in the previous example?
An FXML document defines a variable namespace in which elements can be uniquelly named and
identified.
Assigning an fx:id value to an element creates a variable that can later be referenced.
Above, we use fx:id="myToggleGroup" to setup a name for the toggle group and then use
"$myToggleGroup" to reference it.
The $ is known as the variable resolution operator.
Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017 49

Additionally, if the corresponding object’s type has an id property, then the value will be passed to
the objects setId() method.

11.1.6 Binding expressions


FXML allows one to setup bindings between properties of different controls.
For example, the following binds the text property of a label to the text property of a TextInput
object:
<TextInput f x : i d=” t e x t I n p u t ”/>
<L a b e l t e x t=” $ { t e x t I n p u t . t e x t } ”/>

To distinguish a binding from a simple setting of the property, the variable name must be enclosed by
curly brackets (after the variable resolution operator $).

11.1.7 Event handling


We can add behaviors to elements by defining event handlers for any class that defines a
setOn<Event>() method. Similarly, we can setup listeners for property changes.
There are two ways to do this:

• A script event handler defines the functionality in the FXML file using a scripting language.

• A controller event handler is provided by the Java controller class (discussed below) associated
with the FXML document and the functionality is implemented in Java.

Here is an example of functionality implemented in JavaScript:


<?l a n g u a g e j a v a s c r i p t ?>
...
<VBox>
<c h i l d r e n >
<Button t e x t=” C l i c k Me ! ”
onAction=” j a v a . l a n g . System . out . p r i n t l n ( ’ You c l i c k e d me ! ’ ) ; ”/>
</ c h i l d r e n >
</VBox>

The script part of this construct can be placed in a separate file (called clickme.js, say), to keep the
code separate from the markup for better readability.
For more complex functionality, it is preferable to implement this in your Java program.
The attribute fx:controller allows one to associate a “controller” class with an FXML document.
This class implements the code that corresponds to the object hierarchy defined in the FXML docu-
ment.
Here is a simple example of a controller class:
package mypackage ;
public c l a s s M y C o n t r o l l e r {
public void h a n d l e B u t t o n A c t i o n ( ActionEvent e v e n t ) {
System . out . p r i n t l n ( ”You c l i c k e d me ! ” ) ;
}
}

This is how to reference this in FXML:


<VBox f x : c o n t r o l l e r=” mypackage . M y C o n t r o l l e r ”
xmlns : f x=” h t t p : / / j a v a f x . com/ fxml ”>
<c h i l d r e n >
<Button t e x t=” C l i c k Me ! ” onAction=”#h a n d l e B u t t o n A c t i o n ”/>
</ c h i l d r e n >
</VBox>
50 Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017

Clicking on the button will cause the Java method handleButtonAction(event) to be called and the
text You clicked me! to be written to the console.

11.1.8 The controller class


While the previous example does work, in practice there are two additional issues to discuss.
First, the controller class should implement the interface javafx.fxml.Initializable and provide
a method with this signature:
public void i n i t i a l i z e (URL l o c a t i o n , R e s o u r c e s r e s o u r c e s ) ;

This method gets called once the FXML document has been parsed and allows the program to initialize
stuff.
This is useful in the context of instance variable injection.
For example, consider this FXML code:
<VBox f x : c o n t r o l l e r=”myPackage . M y C o n t r o l l e r ”
xmlns : f x=” h t t p : / / j a v a f x . com/ fxml ”>
<c h i l d r e n >
<Button f x : i d=” button ” t e x t=” C l i c k Me ! ”/>
</ c h i l d r e n >
</VBox>

Here, an identifier fx:id=button is assigned to the button and it can be used in the controller class
to access the button. If the controller class contains a Button member field called button and when
the controller is constructed by the FXML loader, then a reference to the button is “injected” into
the variable.
This allows the following code to work:
package myPackage ;

public c l a s s M y C o n t r o l l e r implements I n i t i a l i z a b l e {
public Button button ; // w i l l g e t i n j e c t e d

@Override
public void i n i t i a l i z e (URL l o c a t i o n , R e s o u r c e s r e s o u r c e s )
button . setOnAction (new EventHandler<ActionEvent >() {
@Override
public void h a n d l e ( ActionEvent e v e n t ) {
System . out . p r i n t l n ( ”You c l i c k e d me ! ” ) ;
} });

In this example, the button must be declared as a public member field to allow injection.
However, we generally do not want to allow direct access to member fields. (This is the second issue.)
To allow injection into private member fields, one can use the FXML annotation:
package myPackage ;

public c l a s s M y C o n t r o l l e r implements I n i t i a l i z a b l e {
@FXML
private Button button ;

@Override
public void i n i t i a l i z e (URL l o c a t i o n , R e s o u r c e s r e s o u r c e s )
button . setOnAction (new EventHandler<ActionEvent >() {
@Override
public void h a n d l e ( ActionEvent e v e n t ) {
System . out . p r i n t l n ( ”You c l i c k e d me ! ” ) ;
} });
}
}
Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017 51

Here is an example that shows how the FXML file is loaded and how one can access the corresponding
controller object. Note that in this example all three files are contained in the same package:
public c l a s s BlastProgram extends A p p l i c a t i o n {
@Override
public void s t a r t ( S t a g e p r i m a r y S t a g e ) throws E x c e p t i o n {
FXMLLoader fxmlLoader=new FXMLLoader ( ) ;
Parent r o o t ;
try ( InputStream i n s=g e t C l a s s ( )
. g e t R e s o u r c e ( ” BlastProgram . fxml ” ) . openStream ( ) ) {
r o o t=fxmlLoader . l o a d ( i n s ) ;
}
B l a s t C o n t r o l l e r b l a s t C o n t r o l l e r=fxmlLoader . g e t C o n t r o l l e r ( ) ;
// can do s o m e t h i n g w i t h t h e c o n t r o l l e r h e r e . . .

p r i m a r y S t a g e . s e t S c e n e (new Scene ( r o o t , 8 0 0 , 6 0 0 ) ) ;
p r i m a r y S t a g e . s e t T i t l e ( ”NCBI B l a s t C l i e n t ” ) ;
p r i m a r y S t a g e . show ( ) ;
}
}

11.2 SceneBuilder
For the project, please use the program SceneBuilder to design your UI. You should use one FXML
file per window or complex dialog.
In the Model-View-Presenter pattern, your FXML files can be considered part of the View, whereas
your controller classes are part of the Presenter (or Controller in MVC).
Please name files so that it is clear how they belong together.
For example, if you are writing a program for viewing PDB files and the main program is implemented
in PDBViewer.java, then the FXML file defining the main GUI should be called PDBViewer.fxml and
the controller program should be called PDBViewerController.java.
Once you have an FXML file in your source tree and you have setup SceneBuilder correctly, then
Intellij will let you launch the program directly like this:

SceneBuilder is an interactive program for setting up your UI. It produces an FXML file as discussed
above.
This is what a simple project might look like in SceneBuilder:
52 Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017

Stuff to add
Contains Properties
layout
Controls
fx:id etc
Menu items of individual
Shapes Editable layout controls
etc

Hierarchy
Set controller here

This is how you define the fx:id for an element (in this case, the apply button). Select the item in
the left hand hierachical view, or in the center layout, and then use the bottom right panel to set the
variable:

The “Show Preview in Window” menu item allows you to test your UI:

The “Show Sample Controller Skeleton” menu item allows you to preview and copy the basic structure
of the controller file that should be associated with this FXML file:
Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017 53

11.3 CSS
What is CSS (Cascading Style Sheets)?2

• A language for describing the presentation of Web pages, including colors, layout, and fonts.

• It allows one to adapt the presentation to different types of displays.

• It is independent of HTML and can be used with any XML-based markup language.

• The separation of HTML from CSS makes it easier to maintain sites, share style sheets across
pages, and tailor pages to different environments. Similar is true for seperation between pro-
gramming logic, FXML and CSS.

• Allows separation of structure and content from presentation.

CSS can be used to determine the presentation of nodes in the JavaFX scene graph. There are three
issues to discuss:

• How to select nodes for styling?

• What properties do nodes have for styling?

• How to actually apply styling to the selected nodes?

This is the general syntax of CSS:


.my-button { color:blue; font-size:12px ...}
selector prop:value prop:value
The selector defines the set of elements to which the style should be applied, whereas the property-value
pairs define the properties and their values.
One can select nodes by their type; use the Java method getTypeSelector() to obtain the type
selector of a node.
Each node in the scene-graph has a styleClass property. This is analogous to the class=... at-
tribute used in HTML and can be used to select by class.
Each node in the scene-graph has a string id and this can be used by id selectors.
We won’t look at this in detail, but here are some examples:
2
Source: https://www.w3.org/standards/webdesign/htmlcss
54 Advanced Java for Bioinformatics, WS’17/18, D. Huson, December 21, 2017

. root {
−fx−f o n t −s i z e : 16 pt ;
−fx−f o n t −f a m i l y : ” C o u r i e r New” ;
−fx−b a s e : rgb ( 1 3 2 , 1 4 5 , 4 7 ) ;
−fx−background : rgb ( 2 2 5 , 2 2 8 , 2 0 3 ) ;
}

Here the selector is the root node of the scene graph and this style is applied to all nodes in the graph.
This code sets the color of a check box that has focus to golden:
. check−box : f o c u s e d {
−fx−c o l o r : g o l d e n ;
}

This is one way to use selection by id:


Button buttonFont = new Button ( ” Font ” ) ;
buttonFont . s e t I d ( ” f o n t −button ” ) ;

We can now specify some CSS for this specific id:


#f o n t −button {
−fx−f o n t : b o l d i t a l i c 20 pt ” A r i a l ” ;
−fx−e f f e c t : dropshadow ( one−pass−box , b l a c k , 8 , 0 . 0 , 2 , 0 ) ;
}

A CSS file can be loaded into a scene like this:


s c e n e . g e t S t y l e s h e e t s ( ) . add ( ” path / myStyle . c s s ” ) ;

CSS styling elements can be applied in Java code like this:


Button aButton = new Button ( ” C o l o r ” ) ;
aButton . s e t S t y l e ( ”−fx−background−c o l o r : s l a t e b l u e ;
−fx−t e x t − f i l l : w h i t e ; ” ) ;

The SceneBuilder program allows one to define CSS for nodes in the FXML file.
For each Node, there are many different properties that can be styled using CSS, see the documentation
for details: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.
html
Here is an example of a styled dialog:

You might also like