Building JavaFX UI Controls - RainFocus | Harness ... · Building JavaFX UI Controls Jonathan Giles...
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
.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
.root {-fx-base: #7eaacc;-fx-background: #7eaacc;-fx-control-inner-background: white;
}
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.|
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.|
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• 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• 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.|
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