Last year, I coded a
custom component on JavaFX 1.x, then naturally I wished to rewrite it on JavaFX 2.0.
To do this, i tried different solutions, like creating to a totally new component with this method.
To do this, i tried different solutions, like creating to a totally new component with this method.
But, it isn't a great
solution when you want to customize or to enhance an existing component, like I
want to do.
To rewrite my custom component, I chose to extend an existing control (TextField in my case) and its skin, because you cannot add content directly in the control but you can do that in its skin.
To rewrite my custom component, I chose to extend an existing control (TextField in my case) and its skin, because you cannot add content directly in the control but you can do that in its skin.
Description
of the implementation
My control's class ( SearchTextBox
) extends the TextField's control and implements my SearchTextBox events (crossButtonOnMouseClicked
& searchEvent).
And my skin's class ( SearchTextBoxSkin ) extends TextFieldSkin to add the reset button in the original TextField.
I also created a new EventType ( SearchTextBoxEvent ) to manage the searchEvent.
And my skin's class ( SearchTextBoxSkin ) extends TextFieldSkin to add the reset button in the original TextField.
I also created a new EventType ( SearchTextBoxEvent ) to manage the searchEvent.
The component code
SearchTextBox.java |
package com.paddyweblog.control; import javafx.event.EventHandler; import javafx.scene.control.TextField; import javafx.scene.input.*; public class SearchTextBox extends TextField{ SearchTextBoxSkin searchTextBoxSkin = new SearchTextBoxSkin(this); EventHandler searchEventHandler = null; EventHandler crossButtonEventHandler = null; SearchTextBox searchTextBox = this; public SearchTextBox(){ super(); this.setSkin(searchTextBoxSkin); this.setOnKeyReleased(new EventHandler<KeyEvent>(){ final KeyCombination combo = new KeyCodeCombination(KeyCode.TRACK_NEXT); @Override public void handle(KeyEvent t) { t.consume(); SearchTextBoxEvent e = new SearchTextBoxEvent(searchTextBox.getText()+t.getCharacter()); searchEventHandler.handle(e); } }); searchTextBoxSkin.crossButton.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent t) { searchTextBox.setText(""); if (crossButtonEventHandler!=null){ crossButtonEventHandler.handle(t); } } }); } public void crossButtonOnMouseClicked(EventHandler eventHandler){ crossButtonEventHandler = eventHandler; } public void searchEvent(EventHandler eventHandler){ searchEventHandler = eventHandler; } }
SearchTextBoxSkin.java |
package com.paddyweblog.control; import com.sun.javafx.scene.control.skin.TextFieldSkin; import javafx.beans.binding.DoubleBinding; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Rectangle; public class SearchTextBoxSkin extends TextFieldSkin{ SearchTextBox searchTextBox; Group crossButton = new Group(); public SearchTextBoxSkin(final SearchTextBox searchTextBox){ super(searchTextBox); this.searchTextBox = searchTextBox; crossButton.setFocusTraversable(false); DoubleBinding crossWidth = searchTextBox.heightProperty().multiply(0.45); DoubleBinding crossHeight = searchTextBox.heightProperty().multiply(0.05); Circle circle = new Circle(); circle.setFill(Color.GRAY); circle.radiusProperty().bind(searchTextBox.heightProperty().multiply(0.325)); circle.setFocusTraversable(false); Rectangle rect1 = new Rectangle(); rect1.widthProperty().bind(crossWidth); rect1.heightProperty().bind(crossHeight); rect1.setFill(Color.WHITE); rect1.setRotate(45); rect1.translateXProperty().bind(crossWidth.divide(2).negate()); rect1.translateYProperty().bind(crossHeight.divide(2).negate()); rect1.setFocusTraversable(false); Rectangle rect2 = new Rectangle(); rect2.widthProperty().bind(crossWidth); rect2.heightProperty().bind(crossHeight); rect2.setFill(Color.WHITE); rect2.setRotate(-45); rect2.translateXProperty().bind(crossWidth.divide(2).negate()); rect2.translateYProperty().bind(crossHeight.divide(2).negate()); rect2.setFocusTraversable(false); crossButton.getChildren().add(circle); crossButton.getChildren().add(rect1); crossButton.getChildren().add(rect2); crossButton.translateXProperty().bind(searchTextBox.widthProperty().subtract(searchTextBox.heightProperty())); crossButton.visibleProperty().bind(searchTextBox.textProperty().greaterThan("")); getChildren().add(crossButton); SearchTextBoxSkin.setAlignment(crossButton,Pos.CENTER_LEFT); this.setPadding(new Insets(3,17,3,3)); } }
SearchTextBoxEvent.java |
package com.paddyweblog.control; import javafx.event.Event; import javafx.event.EventType; public class SearchTextBoxEvent extends Event { public static final EventType<SearchTextBoxEvent> SEARCHTEXTBOXEVENT = new EventType(Event.ANY, "SEARCHTEXTBOXEVENT"); public SearchTextBoxEvent(String text){ super(SEARCHTEXTBOXEVENT); this.text = text; } private String text; public String getText() { return text; } public void setText(String text) { this.text = text; } }
The Application
code, to test the SearchTextBox component
SearchTextBoxControl.java |
package searchtextboxcontrol; import com.paddyweblog.control.SearchTextBox; import com.paddyweblog.control.SearchTextBoxEvent; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.input.MouseEvent; import javafx.stage.Stage; public class SearchTextBoxControl extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Test SearchTextBox control"); Group root = new Group(); Scene scene = new Scene(root, 300, 250); Button btn = new Button(); btn.setLayoutX(10); btn.setLayoutY(100); btn.setText("just a button to change focus"); btn.setOnAction(new EventHandler<ActionEvent>() { public void handle(ActionEvent event) { System.out.println("just a button to change focus"); } }); root.getChildren().add(btn); SearchTextBox stb = new SearchTextBox(); stb.setLayoutX(10); stb.setLayoutY(50); stb.setPrefWidth(150); stb.crossButtonOnMouseClicked(new EventHandler<MouseEvent>(){ @Override public void handle(MouseEvent t) { System.out.println("CrossButtonOnMouseClicked"); } }); stb.searchEvent(new EventHandler<SearchTextBoxEvent>(){ public void handle(SearchTextBoxEvent t) { System.out.println("searchEventHandler : "+t.getText()); } }); root.getChildren().add(stb); primaryStage.setScene(scene); primaryStage.show(); } }
Note: You probably
should to change the Java Platform from the projet properties>librairies (to
choose your JavaFX 2.0 Platform) to run the project in NetBeans
5 commentaires:
Hi,
I have tried example, and it is not working for me. Have you tried with new version of javaFX 2.0.1.
Yes, it works on JavaFX 2.0.1 and 2.0 on Windows and also on Mac OS X.
extend-ui-control-javafx2.0.1.jpg
Which issue do you have ?
Sorry for late response. I am getting this error:
java.lang.NullPointerException
at com.sun.javafx.scene.control.skin.TextInputControlSkin.setCaretAnimating(TextInputControlSkin.java:353)
at com.sun.javafx.scene.control.behavior.TextFieldBehavior.setCaretAnimating(TextFieldBehavior.java:138)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.callAction(TextInputControlBehavior.java:113)
at com.sun.javafx.scene.control.behavior.BehaviorBase.callActionForEvent(BehaviorBase.java:165)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.callActionForEvent(TextInputControlBehavior.java:107)
at com.sun.javafx.scene.control.behavior.BehaviorBase$1.handle(BehaviorBase.java:127)
at com.sun.javafx.scene.control.behavior.BehaviorBase$1.handle(BehaviorBase.java:125)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:56)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:162)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:115)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:47)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
at javafx.event.Event.fireEvent(Event.java:171)
at javafx.scene.Scene$KeyHandler.process(Scene.java:2938)
at javafx.scene.Scene$KeyHandler.access$1700(Scene.java:2868)
at javafx.scene.Scene.impl_processKeyEvent(Scene.java:1431)
at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:1862)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:107)
at com.sun.glass.ui.View.handleKeyEvent(View.java:280)
at com.sun.glass.ui.View.notifyKey(View.java:577)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$2$1.run(WinApplication.java:62)
at java.lang.Thread.run(Thread.java:722)
After investigating, I realized that css of old javafx, that I was using in my application, made this problem.
to extend an existing JavaFX's UI component while maintaining compatibility with FXML, read http://paddyweblog.blogspot.fr/2012/06/custom-component-compatible-with-fxml.html
Enregistrer un commentaire