Building JavaFX UI Controls - RainFocus | Harness ... · Building JavaFX UI Controls Jonathan Giles...

103

Transcript of Building JavaFX UI Controls - RainFocus | Harness ... · Building JavaFX UI Controls Jonathan Giles...

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

BuildingJavaFXUIControls

JonathanGilesConsultingMemberofTechnicalStaffJavaClientTeamOracleCorp

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

SafeHarborStatementThefollowingisintendedtooutlineourgeneralproductdirection.Itisintendedforinformationpurposesonly,andmaynotbeincorporatedintoanycontract.Itisnotacommitmenttodeliveranymaterial,code,orfunctionality,andshouldnotberelieduponinmakingpurchasingdecisions.Thedevelopment,release,andtimingofanyfeaturesorfunctionalitydescribedforOracle’sproductsremainsatthesolediscretionofOracle.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

SessionAgenda

WhatisaUIControl?

ChangesinJDK8andJDK9

WaysToBuildaJavaFXUIControl

UsefulTips/Tools

Q&A

1

2

3

4

5

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Note:IlastgavethistalkatJavaOne 2014.Ifyouattendedthistalk,thecorecontentislargelythesame.But: theseslidesareupdatedtocoverthelatestAPIdevelopmentsinJDK8andJDK9.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

WhatisaUIControl? Visual

Userinteractive

Hasstate

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JavaFX UIControls• UIcontrolsinJavaFX canbelooselydefinedasfollows:

– AJavaFXNode• ItdoesnotnecessarilyextendfromControl• AUIcontrolcouldalsobecanvas-based,butIwon’tcoverthatindepthtoday

– TypicallystyledusingJavaFXCSS• Butnotrequired

– Typicallydesignedtobereusable• Butnotrequired

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

WhatisaNode?• EverythingintheJavaFXscenegraphisaNode.• UIcontrolsconsistofmanyNodes.– Lessisalwaysbetter– Butneedenoughtogetthedesiredstyling

ScrollBar RegionTrackRegionLeftButtonRegion RightButtonRegion

LeftArrowRegion ThumbRegion RightArrowRegion

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

RetainedModeRendering• Forthemostpart,JavaFXuses‘RetainedMode’rendering.• Thisbasicallymeans,wedon’tdrawdirectly,thescenegraph handlesthat.

• Thereisoneexception:theCanvasnodeallowsfor‘immediatemode’rendering.– CanvasisJava2D-like,butwedonotuseitforourJavaFXUIcontrolsatall.– Itremovesallofthepowerofthescenegraph (nolayouts,noCSS,noeventhandling,etc).

– Ithasitsuses….butformostUIcontrolsitisnotthebestoption.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

WhyuseCSS?• “I’maJavadeveloper,nota*censored*CSSexpert!”• Ihearyou– beingaskedtouseCSScanbescaryattheoutset.• Trustme– itispowerfulandvery,veryniceonceyougetusedtoit.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Example:SceneBuilder

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Example:SceneBuilder

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Example:SceneBuilder

.root {-fx-base: rgb(50, 50, 50);-fx-background: rgb(50, 50, 50);-fx-control-inner-background: rgb(50, 50, 50);

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Example:SceneBuilder

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Example:SceneBuilder

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Example:SceneBuilder

.root {-fx-base: #7eaacc;-fx-background: #7eaacc;-fx-control-inner-background: white;

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

ChangesinJDK8

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Controls-relatedchangesinJDK8• JDK8wasreleasedMarch2014,with:– SkinBase wasmadepublicAPI–MoreCSSAPIispublic– Right-to-Leftsupport– Newdefaultstyle(Modena)– Newcontrols(DatePicker,TreeTableView)– Lambdas!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Lambdas// option 1: the old, verbose style

rect.setOnMouseClicked(new EventHandler<MouseEvent>() {

@Override public void handle(MouseEvent event) {

handleMouseEvent(event);

}

});

// option 2: use bracketed lambdas

rect.setOnMouseClicked(event -> {

handleMouseEvent(event);

});

private void handleMouseEvent(MouseEvent event) {System.out.println(event);

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Lambdas// option 3: get rid of brackets

rect.setOnMouseClicked(event -> handleMouseEvent(event));

// option 4: use method reference

rect.setOnMouseClicked(this::handleMouseEvent);

private void handleMouseEvent(MouseEvent event) {System.out.println(event);

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Controls-relatedchangesinJDK8• JDK8u20wasreleasedAugust2014,with:– Ahuge numberofUIcontrolsbugfixes!– CSSAPIimprovements(lesscodingrequired)

• JDK8u40wasreleasedMarch2015,with:– NewUIcontrols(Spinner,FormattedTextField,Dialogs)– AccessibilityAPI(withsupportforallUIcontrols)

• JDK8u60wasreleasedAugust2015,with:– Ahuge numberofUIcontrolsbugfixes!– APIimprovementstoListView,TableView,etc

Bugfixrelease

Featurerelease

Bugfixrelease

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

ThesurfaceareaofaUIcontrol• WritingUIcontrolsisfun,buttheyhaveamassivesurfacearea:– APIdesign– Visuals– Behavior(keyboard/mouse)– Unittesting– Documentation– Accessibility(screenreaders)– Right-to-leftlayout

• WhennewfunctionalityarrivesinJavaFX(e.g.a11yorRTL),allcontrolsneedupdating!

Confidential– OracleInternal/Restricted/HighlyRestricted 23

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Controls-relatedchangescominginJDK9• Sincefreezingon8u60,focushasbeenprimarilyonJDK9,comingin2017.

• JDK9isthe‘jigsaw’/modulesrelease.– Ahuge amountofworkhasbeenexpendedonmodules!–Modulesateupnearlyall‘feature’time.

• ForUIcontrols:– PrimaryfocushasbeenonJEP253–Morethan175bugfixesand16enhancementsincontrolsaswell

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell• MostUIcontrolsaresplitintothreecomponents:

Control

Behavior

Skin

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell• MostUIcontrolsaresplitintothreecomponents:

Control

Behavior

Skin

PublicAPI(javafx.scene.control)

PrivateImplementation(com.sun.javafx.scene.control.*)

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell• UIControlsandCSSAPIshavealwayshadpublicAPIand‘private’API–Manyprojectscan’tresisttheurgetousecom.sun.*API.– Alwaysfrownedupon,butneverprevented(andimpossibletopreventanyway).

• JDK9withJigsawmodularityisabiggamechanger:– UpuntilJDK9,developerscoulduseAPIincom.sun.*packages.– JDK9enforcesboundaries- com.sun.*becomesunavailable

• SomeJavaFXappsandlibrarieswillfailtocompile/executeunderJDK9.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell

Control

Behavior

Skin

PublicAPI(javafx.scene.control)

PrivateImplementation(com.sun.javafx.scene.control.*)

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell• WhydopeopleneedtousetheseAPIs?

• Manyapplicationsneedfunctionalitywejusthaven’tgotaroundtomakingpublicyet!

• Manycustomcontrolsbasetheirskinsonexistingskins,e.g.– CustomTextFieldSkin extendsTextFieldSkin– TextFieldSkin nolongeravailableatcompiletime

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell

Control

Behavior

Skin

PrivateImplementation(com.sun.javafx.scene.control.*)

PublicAPI(javafx.scene.control)

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell

Control

Behavior

Skin

PublicAPI(javafx.scene.control) PrivateImplementation

(com.sun.javafx.scene.control.*)

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JEP253InANutshell• Overall,JEP253is’finished’(barringinternaltesting):– AllcodehasbeenmergedintoJDK9mainrepoforoverayear

• It’scritical thatthecommunitytestandgivefeedbackonJDK9assoonaspossible!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

WaysToBuildaJavaFXUIControl

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Overview• WhatconstitutesaUIcontrolislooselydefined.

• Planfortoday:– FourdifferentwaystobuildaUIcontrol– startwithsimplest…–…ThentransformittobeclosertowhatIdoinmydayjob,i.e.a‘proper’Control.

• Whatarewegoingtobuild?

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Introducing:TheJavaOneButton!• Ourrequirements:–Ourclienthascometouswithanewproject– Veryspecific UIdesignrequirements!–Mustrespondtomouseevents–Mustgiveavisualindicationofbeinginnormal,pressed,andhoveredstates

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Code• Don’tworryabouttakingnotesofthecodeintheseslides.

• Allcodedemonstratedisavailableonline:

http://bitbucket.org/JonathanGiles/javaone-controls

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

OptionsforBuildingCustomControls

Therearefourmainapproaches:1. CustomiseanexistingcontrolwithCSS2. Customiseanexistingcontrolbyreplacingtheskin3. Creatinganewcontrolbyextendingalayoutcontainer4. CreatinganewcontrolbyextendingfromtheControlclass

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option1:CustomiseAnExistingControlWithCSS

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option1:CustomiseAnExistingControlwithCSS• Momentofclarity!• JavaOneButton soundsremarkably liketheJavaFX Buttoncontrol• Unfortunately,itlooksnothinglikemyclientwantsittolooklike…

• CSStotherescue!

!=

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option1:CustomiseAnExistingControl

public class JavaOneButton extends Button {

public JavaOneButton(String text) {

super(text);

getStyleClass().add("javaone-button");

}

}

JavaCode:.javaone-button {

-fx-base: red;-fx-rotate: -5;-fx-scale-x: 2.5;-fx-scale-y: 2.5;

}

CSS:

modena.css/caspian.css

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option1:CustomiseAnExistingControl

Button normalButton = new Button("Disappointing Normal Button");

JavaOneButton javaOneButton = new JavaOneButton("Hello JavaOne!");

scene.getStylesheets().add(JavaOneButton.class.getResource("javaone-button.css").toExternalForm());

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option1:CustomiseAnExistingControl

Success!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option1Discussion

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

1:WascreatingJavaOneButton necessary?• Itwasnot necessary• Wecouldhavejustdonethis:

– Problemwiththisapproach:• Lessreusable(everyonemustalwaysdothesecondline)• Morepronetorefactoringerrors• Moreverbose

Button javaOneButton = new Button("Hello JavaOne!");javaOneButton.getStyleClass().add("javaone-button");

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

2:Wascreatinga‘javaone-button’styleclassnecessary?• AllJavaFXUIcontrolshavedefaultstyleclassessetinthem– E.g.Buttonhas.button

• So,whydidn’twejustusethe.button styleclass?

.button {-fx-base: red;-fx-rotate: -5;-fx-scale-x: 2.5;-fx-scale-y: 2.5;

}

.javaone-button {-fx-base: red;-fx-rotate: -5;-fx-scale-x: 2.5;-fx-scale-y: 2.5;

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

2:Wascreatinga‘javaone-button’styleclassnecessary?

Itmightnotbewhatyouwant!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

3:CanweremoverequirementtomanuallyimportCSSfile?• Itispossible toavoidrequiringuserstomanuallyimportthecss file.– Ratherthantheend-userdoingthis:

–WecouldhaveaddedthefollowingcodetoJavaOneButton:

• Endresult:CSSisencapsulatedinsidethecustomcontrol(whereitbelongs)

scene.getStylesheets().add(JavaOneButton.class.getResource("javaone-button.css").toExternalForm());

@Override public String getUserAgentStylesheet() {return JavaOneButton.class.getResource("javaone-button.css").toExternalForm();

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

3:CanweremoverequirementtomanuallyimportCSSfile?

Button normalButton = new Button("Disappointing Normal Button");

JavaOneButton javaOneButton = new JavaOneButton("Hello JavaOne!");

scene.getStylesheets().add(JavaOneButton.class.getResource("javaone-button.css").toExternalForm());

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option1:InConclusion• IfaUIcontrolexistswiththeAPIyouwant,andtheskinisalreadyprettymuchwhatyouwant…option1shouldworkforyou!• Itispossibletoencapsulateallchangestothecontrolinanewsubclass,e.g.JavaOneButton• Developerdoesnotneedtodoanythingspecialtouseit

• I’llbebrieflytalkingaboutthisagaintomorrowat11am:‘WelcometotheNextLevel:Java9+Gluon+Mobile’

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option2:CustomiseAnExistingControlByReplacingTheSkin

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option2:Customisecontrolwithnewskin• SometimestherearejustnotenoughnodesintheexistingskinforCSStostyle.

ScrollBar RegionTrackRegionLeftButtonRegion RightButtonRegion

LeftArrowRegion ThumbRegion RightArrowRegion

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option2:Customisecontrolwithnewskin• SometimestherearejustnotenoughnodesintheexistingskinforCSStostyle.

• Creatingacustomskinallowsustotalfreedomtoputinthenodesthatweneed.

ScrollBar RegionLeftofThumbRegionLeftButtonRegion RightButtonRegion

LeftArrowRegion ThumbRegion RightArrowRegionRightofThumbRegion

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option2:Customisecontrolwithnewskin• Wewillcovercustomskinsmorewhenwegettooption4.

• Brieflythough,therearetwooptions:– Startinganewskinfromscratch(coveredlaterinoption4)– StartinginJDK9,allJavaFXUIcontrolskinsarepublicAPI• Thismeansthatyoucan,ifdesired,extendfromthem

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option2:Customisecontrolwithnewskin• Onceanewskiniscreated:– Createasubclassofthecontrol,–Overide createDefaultSkin,e.g.:

@Override protected Skin<?> createDefaultSkin() {

return new CustomButtonSkin(this);

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer• OK– Optiononeandtwoseemsperfect,whywouldweeveruseadifferentapproach?

• Afewreasons:– TheUIcontrolAPIyouwantmightnotexist.Someonehastobuildthefirstone!–WhatifthebehaviourorvisualsoftheUIcontrolarenotasyouwant.• APIorfunctionalitymightbetooinflexible(ortooflexible)foryourliking

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer

• “ExtendfromaJavaFXlayoutcontainer???”– Butwhichone?!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer

Node

Parent

Region

Pane

AnchorPane BorderPane FlowPane GridPane HBox StackPane TilePane VBox

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Node

Parent

Region

Pane

AnchorPane BorderPane FlowPane GridPane HBox StackPane TilePane VBox

Option3:ExtendALayoutContainer

Node:Never!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Node

Parent

Region

Pane

AnchorPane BorderPane FlowPane GridPane HBox StackPane TilePane VBox

Option3:ExtendALayoutContainer

Parent:Addsconceptofprotectedchildren.

NotoverlyCSSstyleable.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Node

Parent

Region

Pane

AnchorPane BorderPane FlowPane GridPane HBox StackPane TilePane VBox

Option3:ExtendALayoutContainer

Region:EssentiallyamoreCSSstyleable Parent.

Childrenliststillprotected,sogoodifyoudon’twantpeoplemodifyinglist.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Node

Parent

Region

Pane

AnchorPane BorderPane FlowPane GridPane HBox StackPane TilePane VBox

Option3:ExtendALayoutContainer

Pane:PaneisaRegion,butwithapubliclyaccessiblechildrenlist.

Goodifyouwantpeopletomodifychildren.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Node

Parent

Region

Pane

AnchorPane BorderPane FlowPane GridPane HBox StackPane TilePane VBox

Option3:ExtendALayoutContainer

Layoutcontainers:Greatifyouwanttousethepre-specifiedlayoutalgorithm.

Commonlyused:StackPane,HBox,VBox,BorderPane

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer• ForJavaOneButton,wecouldreasonablypicktwooptions:– Region:• Pros:CSSstyleable,nopublicAPIaccesstochildrenlist• Cons:Wehavetowritethelayoutcodeourselves

– StackPane:• Pros:CSSstyleable,defaultlayoutalgorithmwillsufficeforatext-onlybutton• Cons:We’releakingmoreAPIthandesirable(wedon’twantpeopletomodifychildrendirectly)

• Mypreferenceinthiscase:useRegion

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

public class JavaOneButton extends Region {

private static final PseudoClass PSEUDO_CLASS_ARMED =PseudoClass.getPseudoClass("armed");

private final Label textLabel;

public JavaOneButton(String text) {

getStyleClass().add("javaone-button");

setFocusTraversable(true);

textLabel = new Label();

textLabel.textProperty().bind(textProperty);

getChildren().add(textLabel);

setText(text);

addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {

pseudoClassStateChanged(PSEUDO_CLASS_ARMED, true);

requestFocus();

});

addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {

pseudoClassStateChanged(PSEUDO_CLASS_ARMED, false);

});

}

// --- textprivate StringProperty textProperty =

new SimpleStringProperty(this, "text");

public final StringProperty textProperty() { return textProperty; }

public final String getText() { return textProperty.get(); }

public final void setText(String text) { textProperty.set(text); }

Option3:ExtendALayoutContainer

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer@Override protected double computeMinWidth(double height) {

return textLabel.minWidth(height);

}

@Override protected double computeMinHeight(double width) {

return textLabel.minHeight(width);

}

@Override protected double computeMaxWidth(double height) {

return computePrefWidth(height);

}

@Override protected double computeMaxHeight(double width) {

return computePrefHeight(width);

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer@Override protected double computePrefWidth(double height) {

return textLabel.prefWidth(height) +

snappedLeftInset() +

snappedRightInset();

}

@Override protected double computePrefHeight(double width) {

return textLabel.prefHeight(width) +

snappedTopInset() +

snappedBottomInset();

} textLabel

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer@Override protected void layoutChildren() {

final double x = snappedLeftInset();

final double y = snappedTopInset();

final double w = getWidth() - (snappedLeftInset() + snappedRightInset());

final double h = getHeight() - (snappedTopInset() + snappedBottomInset());

textLabel.resizeRelocate(x, y, w, h);

}

x

y

w

htextLabel

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer@Override public String getUserAgentStylesheet() {

return JavaOneButton.class.getResource("javaone-button.css").toExternalForm();

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer.javaone-button {

-fx-base: red;-fx-rotate: -5;-fx-scale-x: 2.5;-fx-scale-y: 2.5;

/* This section copied verbatim from modena.css */-fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;-fx-background-insets: 0 0 -1 0, 0, 1, 2;-fx-background-radius: 3px, 3px, 2px, 1px;-fx-padding: 0.333333em 0.666667em 0.333333em 0.666667em; /* 4 8 4 8 */-fx-text-fill: -fx-text-base-color;-fx-alignment: CENTER;-fx-content-display: LEFT;

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer

.javaone-button:armed {-fx-color: -fx-pressed-base;

}

.javaone-button:hover {-fx-color: -fx-hover-base;

}

.javaone-button:focused {/* This section copied verbatim from modena.css */-fx-background-color: -fx-focus-color, -fx-inner-border, -fx-body-color, -fx-faint-focus-color, -fx-body-color;-fx-background-insets: -0.2, 1, 2, -1.4, 2.6;-fx-background-radius: 3, 2, 1, 4, 1;

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer

Success!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option3:ExtendALayoutContainer– AFewComments

• Option3requiresmorecoding…

• …Butitgivesusmuchmorecontroltodowhatwewant

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl• Thistakesustooption4– usingtheJavaFXControlAPI

• Thisisdifferentfromoption2:–Option2extendsfromaControlsubclass,e.g.Button–Option4extendsfromControlitself

• Thisapproachresultsinthecleanestcode– Separationofstatefromvisuals– EasiertoshipAPIinseparateclassfromimplementation• UseseparatepackagesforAPIandimpl,thenhideimpl fromjavadoc and/orusemodules!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl

Node

Parent

Region

Control Pane

AnchorPane BorderPane FlowPane GridPane HBox StackPane TilePane VBox

Control:Childrenlistremainsprotected.

AddsconceptofSkins–everyControlcanhaveaSkintohandleitslayout.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl• Inessence,wesplittheOption3JavaOneButton classintotwoclasses:– JavaOneButton extendsfromControl,insteadofRegion– JavaOneButtonSkin extendsfromSkinBase

• Letsgetintothecode!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControlpublic class JavaOneButton extends Control {

public JavaOneButton(String text) {

getStyleClass().add("javaone-button");

setFocusTraversable(true);

setText(text);

}

// --- text

private StringProperty textProperty = new SimpleStringProperty(this, "text");

public final StringProperty textProperty() { return textProperty; }

public final String getText() { return textProperty.get(); }

public final void setText(String text) { textProperty.set(text); }

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl@Override public String getUserAgentStylesheet() {

return JavaOneButton.class.getResource("javaone-button.css").toExternalForm();

}

@Override protected Skin<?> createDefaultSkin() {

return new JavaOneButtonSkin(this);

}

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControlpublic class JavaOneButtonSkin extends SkinBase<JavaOneButton> {

private static final PseudoClass PSEUDO_CLASS_ARMED = PseudoClass.getPseudoClass("armed");

private final Label textLabel;

protected JavaOneButtonSkin(JavaOneButton control) {

super(control);

textLabel = new Label();

textLabel.textProperty().bind(control.textProperty());

getChildren().add(textLabel);

control.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {

pseudoClassStateChanged(PSEUDO_CLASS_ARMED, true);

control.requestFocus();

});

control.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> pseudoClassStateChanged(PSEUDO_CLASS_ARMED, false));

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl@Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {

return textLabel.minWidth(height);

}

@Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {

return textLabel.minHeight(width);

}

@Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {

return textLabel.prefWidth(height) + leftInset + rightInset;

}

@Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {

return textLabel.prefHeight(width) + topInset + bottomInset;

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl@Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {

return computePrefWidth(height, topInset, rightInset, bottomInset, leftInset);

}

@Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {

return computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);

}

@Override protected void layoutChildren(double x, double y, double w, double h) {

textLabel.resizeRelocate(x, y, w, h);

}

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl• TheCSSremainsexactly thesameaswehadinoption3.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl

Button normalButton = new Button("Disappointing Normal Button");

JavaOneButton javaOneButton = new JavaOneButton("Hello JavaOne!");

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Option4:ExtendFromControl

Success!

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

UsefulTips/Tools

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

CSSStyleable Properties• WecoveredCSSpseudoclassesinoptions3and4– Recallapseudoclassisthepartafterthecolon,e.g.‘hover’:

• Butwedidn’tcoverhowtocreatecustomstyleable properties– E.g.,‘javaone-year’:

.javaone-button:hover {-fx-color: -fx-hover-base;

}

.javaone-button {javaone-year: 2014;

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

CSSStyleable Propertiespublic class JavaOneButton extends Button {

private static final StyleablePropertyFactory<JavaOneButton> FACTORY = new StyleablePropertyFactory<>(Button.getClassCssMetaData());

private final StyleableProperty<Integer> javaoneYear =FACTORY.createStyleableIntegerProperty(this, "javaoneYear", "javaone-year", s -> s.javaoneYear);

// Typical JavaFX property implementationpublic final IntegerProperty javaoneYearProperty() { return (IntegerProperty)javaoneYear; }public final int getJavaoneYear() { return javaoneYear.getValue(); }public final void setJavaoneYear(int value) {javaoneYear.setValue(value); }

@Override public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {return FACTORY.getCssMetaData();

}

}

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

MultipleStyleClasses• InJavaFXyoucanhavemultiplestyleclassesonanode.• Forexample,youcouldadd‘javaone’toasingleButtoninstance,soyou’dhavetwostyleclasses:‘javaone’and‘button’.

• YoucanthenhaveCSSlikethis:.button {

-fx-color: gray;}.button.javaone {

-fx-color: red;}

Confidential– OracleInternal/Restricted/HighlyRestricted 89

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

GetToKnowModena/Caspian• UIcontrolsareentirelystyledviaCSSstyles– JavaFX 2.x– Caspian– JavaFX8.x– Modena

• IfyouwanttoknowhowUIcontrolsarestyled,thesearetheauthoritativesource.

• Filesareincom.sun.javafx.scene.control.skin package.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

RefertotheCSSReferenceGuidehttp://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

Scenegraph Updates• Don’tmodifythescenegraph needlessly– thisisn’tfree!– Togglevisibilityinstead(ifthenumberofnodesissmall)

• JavaFX updatesthescreenat60FPS– Eventscanfireatmanytimesthisrate– Don’tbetemptedtoupdatetheUIoneveryevent– itwon’tmaketheUIanymore‘fluid’.

– AgoodwaytodothisistobatchupyourworkandrunatthestartofthelayoutChildren()method.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

JoinTheOpenJFX Community• Jointheopenjfx-dev mailinglistandstartcontributing!– http://openjdk.java.net/projects/openjfx/

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

FileBugReports• Don’tassumethatweknoweverybugthatexists!Wedon’t.• Reportbugreports,anddiscussyourissuesontheopenjfx-devmailinglist

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

UseScenicView!• ScenicViewisafree,opensourceJavaFXscenegraph analyser.

• DownloadandfindoutmoreaboutScenicViewhere:– http://www.scenic-view.org

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.| 96

Treeshowingscenegraphstructureofrunning

application

Themostimportant

propertiesfortheselectednode

Applicationoverview

ScenicViewinaNutshell

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

ScenicViewinaNutshell ScenicViewcandrawoverlaysintheapplication

itisobserving.

ThegreendashedrectangleshowsthelayoutBounds,andtheyellowfilledrectangleshowstheboundsInParent.

Thiscanbeveryusefulfordebugging.

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

FXExperience• FollowtheFXExperienceblogforthelatestnews/geekery onJavaFX– http://www.fxexperience.com

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

ComingUpTonight:MeettheOracleJavaFXandJDK Client Team,inhere7:00pm– 7:45pmJavaFXScenicViewBOF,inhere8:00pm– 8:45pm

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

ComingUpTomorrow:Gerrit Grunwald andToddCostella arepresentingahands-onlabonJavaFXControls.

CustomizeYourJavaFXControlsTuesday,Sep20,8:30a.m.- 10:30a.m.|Hilton—FranciscanRoomC/D

Copyright©2016, Oracleand/oritsaffiliates.Allrightsreserved.|

ThanksforAttending!

It’sQuestion&AnswerTime!Email:[email protected]:@JonathanGiles

Remember,allcodefromthistalkisavailablehere:http://bitbucket.org/JonathanGiles/javaone-controls