In November, last year, I wrote a little example on how to extend an existing component in JavaFx 2.0.
Today, I would use this component in FXML and make a little demo.
The application for the demo is very simple:
Today, I would use this component in FXML and make a little demo.
The application for the demo is very simple:
- One SearchTextBox component (custom component) with events on OnCrossButtonMouseClicked and OnSearchEvent.
- One ComboBox to change the font size of the SearchTextBox component.
- Add a method to change font of the SearchTextBox component (and thus its font size)
- Fix some bugs
- Add the FXML compatibility to the SearchTextBox component.
Add the font change and fix bugs
First, I began by adding the methods to change the font of the SearchTextBox component.
public Font getFont(){
return searchTextBoxSkin.fontProperty.getValue();
}
public void setFont(Font font){
searchTextBoxSkin.fontProperty.setValue(font);
}
Then, I have fixed some bugs...
(For example: in the skin class (SearchTextBoxSkin) of the component to correctly render the cross button with any font size
or in the implementation of the method handle(KeyEvent t)in the SearchTextBox class)
First, I began by adding the methods to change the font of the SearchTextBox component.
public Font getFont(){
return searchTextBoxSkin.fontProperty.getValue();
}
public void setFont(Font font){
searchTextBoxSkin.fontProperty.setValue(font);
}
Then, I have fixed some bugs...
(For example: in the skin class (SearchTextBoxSkin) of the component to correctly render the cross button with any font size
or in the implementation of the method handle(KeyEvent t)in the SearchTextBox class)
Add the FXML compatibility to the SearchTextBox component
Normally to use the SearchTextBox component it in FXML, you should write something like this:
<SearchTextBox fx:id="searchTextBox1" crossButtonMouseClicked="#handleSearchTextBoxCrossButtonOnMouseClicked"
searchEvent="#handleSearchTextBoxSearchEvent">
</SearchTextBox>
Normally to use the SearchTextBox component it in FXML, you should write something like this:
<SearchTextBox fx:id="searchTextBox1" crossButtonMouseClicked="#handleSearchTextBoxCrossButtonOnMouseClicked"
searchEvent="#handleSearchTextBoxSearchEvent">
</SearchTextBox>
But, it isn't working because:
1. An FXML's attribute must have a getter and a setter corresponding to it into the component (my 2 attributes, crossButtonMouseClicked and searchEvent, don't have them)
2. The name of the FXML's attribute must begin by on to receive an EventHandler as parameter for the setter corresponding to it in the component. If the attribute doesn't begin by on, the setter will receive a String which contains the value of the attribute.
So, I added the getters and setters in SearchTextBox
public void setOnCrossButtonMouseClicked (EventHandler eventHandler){
crossButtonEventHandler = eventHandler;
}
public EventHandler getOnCrossButtonMouseClicked (){
return crossButtonEventHandler;
}
public void setOnSearchEvent(EventHandler eventHandler){
searchEventHandler = eventHandler;
}
public EventHandler getOnSearchEvent(){
return searchEventHandler;
}
And, I have deprecated the methods crossButtonOnMouseClicked and searchEvent.
Now, to use the SearchTextBox component in FXML, you have to write something like this:
<SearchTextBox fx:id="searchTextBox1" onCrossButtonMouseClicked="#handleSearchTextBoxCrossButtonOnMouseClicked"
onSearchEvent="#handleSearchTextBoxSearchEvent">
</SearchTextBox>
Note: The complete source code of the SearchTextBox component is available at the end of this post.
Make the application
Now, with a custom component working in FXML, write the demo is very simple.
The application consists of:
Now, to use the SearchTextBox component in FXML, you have to write something like this:
<SearchTextBox fx:id="searchTextBox1" onCrossButtonMouseClicked="#handleSearchTextBoxCrossButtonOnMouseClicked"
onSearchEvent="#handleSearchTextBoxSearchEvent">
</SearchTextBox>
Note: The complete source code of the SearchTextBox component is available at the end of this post.
Make the application
Now, with a custom component working in FXML, write the demo is very simple.
The application consists of:
- the FXML to describe the UI
- the controller of the FXML, which contains the code to interact with the UI.
- and the JavaFX application to load the FXML and use it.
The FXML
The component
The custom event
NetBeans project
Screen1.fxml |
<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.collections.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.paint.*?> <?import com.paddyweblog.control.*?> <VBox id="vBox1" prefWidth="300.0" prefHeight="200.0" spacing="10.0" xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlusercomponent.Screen1"> <children> <HBox id="hBox1" alignment="CENTER" spacing="10.0" > <children> <Label id="label1" contentDisplay="CENTER" text="Size font Text Search Text Box" /> <ComboBox id="comboBox1" fx:id="comboBox1" onAction="#handleComboBoxAction" > <items> <FXCollections fx:factory="observableArrayList"> <String fx:value="10" /> <String fx:value="13" /> <String fx:value="15" /> <String fx:value="20" /> <String fx:value="25" /> <String fx:value="30" /> <String fx:value="35" /> <String fx:value="40" /> <String fx:value="45" /> </FXCollections> </items> </ComboBox> </children> </HBox> </children> <children> <SearchTextBox fx:id="searchTextBox1" onCrossButtonMouseClicked="#handleSearchTextBoxCrossButtonOnMouseClicked" onSearchEvent="#handleSearchTextBoxSearchEvent"> </SearchTextBox> </children> </VBox>The controller
Screen1.java |
package fxmlusercomponent; import com.paddyweblog.control.SearchTextBox; import com.paddyweblog.control.SearchTextBoxEvent; import java.net.URL; import java.util.ResourceBundle; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.ComboBox; import javafx.scene.input.MouseEvent; import javafx.scene.text.Font; public class Screen1 implements Initializable { @FXML private ComboBox comboBox1; @FXML private SearchTextBox searchTextBox1; @FXML private void handleComboBoxAction(ActionEvent event) { Font f = searchTextBox1.getFont(); String name = f.getName(); double sizeValue = Double.parseDouble((String)comboBox1.getValue()); Font fnew = new Font(name,sizeValue); searchTextBox1.setFont(fnew); } @FXML private void handleSearchTextBoxCrossButtonOnMouseClicked(MouseEvent mouseEvent){ System.out.println("handleSearchTextBoxCrossButtonOnMouseClicked"); } @FXML private void handleSearchTextBoxSearchEvent(SearchTextBoxEvent searchTextBoxEvent){ System.out.println("handleSearchTextBoxSearchEvent"+searchTextBoxEvent.getText()); if ("aaaa".equals(searchTextBoxEvent.getText())){ System.out.println("Good !"); } } @Override public void initialize(URL url, ResourceBundle rb) { Font f = searchTextBox1.getFont(); comboBox1.setValue(String.valueOf((int)f.getSize())); } }The JavaFX application
FxmlUserComponent.java |
package fxmlusercomponent; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class FxmlUserComponent extends Application { public static void main(String[] args) { Application.launch(FxmlUserComponent.class, args); } @Override public void start(Stage stage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("Screen1.fxml")); stage.setScene(new Scene(root)); stage.show(); } }Source code of the SearchTextBox component
The component
SearchTextBox.java |
package com.paddyweblog.control; import javafx.event.EventHandler; import javafx.scene.control.TextField; import javafx.scene.input.*; import javafx.scene.text.Font; 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()); SearchTextBoxEvent e = new SearchTextBoxEvent(searchTextBox.getText()); if (searchEventHandler!=null){ 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 setOnCrossButtonMouseClicked (EventHandler eventHandler){ crossButtonEventHandler = eventHandler; } public EventHandler getOnCrossButtonMouseClicked (){ return crossButtonEventHandler; } public void setOnSearchEvent(EventHandler eventHandler){ searchEventHandler = eventHandler; } public EventHandler getOnSearchEvent(){ return searchEventHandler; } @Deprecated public void crossButtonOnMouseClicked(EventHandler eventHandler){ crossButtonEventHandler = eventHandler; } @Deprecated public void searchEvent(EventHandler eventHandler){ searchEventHandler = eventHandler; } public Font getFont(){ return searchTextBoxSkin.fontProperty.getValue(); } public void setFont(Font font){ searchTextBoxSkin.fontProperty.setValue(font); } }The component skin
SearchTextBoxSkin.java |
package com.paddyweblog.control; import com.sun.javafx.scene.control.skin.TextFieldSkin; import javafx.beans.binding.DoubleBinding; import javafx.beans.property.ObjectProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; 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; import javafx.scene.text.Font; public class SearchTextBoxSkin extends TextFieldSkin{ SearchTextBox searchTextBox; Group crossButton = new Group(); ObjectProperty<Insets> paddingProperty = this.paddingProperty(); ObjectProperty<Font> fontProperty = this.font; 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); searchTextBox.heightProperty().addListener(new ChangeListener(){ public void changed(ObservableValue ov, Object t, Object t1) { Double d = (Double)t1; paddingProperty.set(new Insets(3,d.intValue(),3,3)); } } ); } }
The custom event
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; } }
NetBeans project
2 commentaires:
good post and with useful information
But i like the assertions in java
Hi
Do you have something against using fragments of your code in commercial project? I couldn't find any note about license on your blog.
Enregistrer un commentaire