How to add a custom component to a JavaFX TableView column? - javafx

I want to add a custom component (SwitchButton) to a column in a JavaFX TableView. I've looked at some examples with buttons and I'm just not understanding so far how to do it. Below is my practice table code along with the SwitchButton code I want to be able to put in the Active/Inactive column. The value for the SwitchButton (Active or Inactive) will be read from the database and when the user switches it, I'll want to trigger an action to write it to the database.
TableWithSwitchButtonView.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="248.0" prefWidth="271.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabletest.TableWithSwitchButtonController">
<children>
<TableView fx:id="configTableView" prefHeight="240.0" prefWidth="271.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="configColumn" prefWidth="138.0" text="Configuration Name" />
<TableColumn fx:id="activeColumn" prefWidth="131.0" text="Active/Inactive" />
</columns>
</TableView>
</children>
</AnchorPane>
TableWithSwitchButtonController.java:
package tabletest;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class TableWithSwitchButtonController implements Initializable
{
#FXML
private TableColumn<Config, String> configColumn;
#FXML
private TableColumn<Config, String> activeColumn;
#FXML
private TableView<Config> configTableView;
#Override
public void initialize(URL url, ResourceBundle rb)
{
// Add Cell Value Factory
configColumn.setCellValueFactory(new PropertyValueFactory<Config,
String>("configName"));
activeColumn.setCellValueFactory(new PropertyValueFactory<Config,
String>("configActive"));
// populate the Column lists (this will be coming from the database)
ObservableList<Config> configList =
FXCollections.<Config>observableArrayList(
new Config("Config 1", "active"),
new Config("Config 2", "active"),
new Config("Config 3", "inactive")
);
configTableView.getItems().addAll(configList);
}
public class Config
{
private String configName;
private String configActive;
public Config(String name, String active)
{
configName = name;
configActive = active;
}
public String getConfigName()
{
return configName;
}
public void setConfigName(String name)
{
configName = name;
}
public String getConfigActive()
{
return configActive;
}
public void setConfigActive(String active)
{
configActive = active;
}
};
}
TableTest.java:
package tabletest;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TableTest extends Application
{
#Override
public void start(Stage primaryStage)
{
try
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("TableWithSwitchButtonView.fxml"));
Scene scene = new Scene((Parent) loader.load());
primaryStage.setScene(scene);
primaryStage.setTitle("Table Test");
primaryStage.show();
}
catch (IOException ignored)
{
}
}
public static void main(String[] args)
{
launch(args);
}
}
SwitchButton.java:
package tabletest;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
public class SwitchButton extends Label
{
private SimpleBooleanProperty switchedOn = new SimpleBooleanProperty(true);
public SwitchButton()
{
Button switchBtn = new Button();
switchBtn.setPrefWidth(40);
switchBtn.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent t)
{
switchedOn.set(!switchedOn.get());
}
});
setGraphic(switchBtn);
switchedOn.addListener(new ChangeListener<Boolean>()
{
#Override
public void changed(ObservableValue<? extends Boolean> ov,
Boolean t, Boolean t1)
{
if (t1)
{
setText("ACTIVE");
setStyle("-fx-background-color: green;-fx-text-fill:white;");
setContentDisplay(ContentDisplay.RIGHT);
}
else
{
setText("INACTIVE");
setStyle("-fx-background-color: grey;-fx-text-fill:black;");
setContentDisplay(ContentDisplay.LEFT);
}
}
});
switchedOn.set(false);
}
public SimpleBooleanProperty switchOnProperty() { return switchedOn; }
}

Related

JavaFX Custom control does not appear in Scene

I started to learn JavaFX for couple of days. I took a lot of stackoverflow examples, google-it, youtube videos, and all seems good in examples, but mine does not work and I don't know what I'm doing wrong.
So, I make tests only for now, nothing important, it is not an application in real world.
I've built a Custom Control using SceneBuilder, so this is the fxml file for it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="cControl" prefHeight="100.0" prefWidth="100.0"
style="-fx-border-color: #111111; -fx-border-radius: 2; -fx-background-color: linear-gradient(from 50% 0% to 50% 100%, #f0f0f0, orangered); -fx-background-radius: 2;"
xmlns="http://javafx.com/javafx/19"
xmlns:fx="http://javafx.com/fxml/1"
>
<children>
<Button fx:id="btnClickMe" layoutX="12.0" layoutY="67.0" mnemonicParsing="false" onAction="#onClickMeAction" prefHeight="25.0" prefWidth="77.0" text="Button" AnchorPane.bottomAnchor="8.0" />
<Label fx:id="lblTitle" alignment="CENTER" contentDisplay="CENTER" focusTraversable="false" layoutY="1.0" prefHeight="43.0" prefWidth="100.0" text="Label" textAlignment="CENTER" AnchorPane.bottomAnchor="56.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="1.0" />
</children>
</AnchorPane>
The model is this:
PackTestModel.java
package com.myapp.customcontrols;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class PackTestModel {
public PackTestModel(String labelText) {
setLabelText(labelText);
}
public String getLabelText() {
return labelText.get();
}
public StringProperty labelTextProperty() {
return labelText;
}
public void setLabelText(String labelText) {
this.labelText.set(labelText);
}
private final StringProperty labelText = new SimpleStringProperty();
}
This is the controller:
package com.myapp.customcontrols;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import java.net.URL;
import java.util.ResourceBundle;
public class PackTestController implements Initializable {
#FXML
private Button btnClickMe;
#FXML
private Label lblTitle;
private final PackTestModel packTestModel;
public PackTestController(PackTestModel ptm) {
packTestModel = ptm;
}
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
lblTitle.textProperty().bind(packTestModel.labelTextProperty());
}
}
This is the code for my CustomControl class:
package com.myapp.customcontrols;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
public class PackTestCC extends AnchorPane {
private PackTestController packTestController;
public PackTestCC(PackTestModel model) throws IOException {
super();
FXMLLoader loader = new FXMLLoader(getClass().getResource("PackTest.fxml"));
packTestController = new PackTestController(model);
loader.setController(packTestController);
try {
Node n = loader.load();
this.getChildren().add(n);
}catch (RuntimeException e){}
}
}
And my main application Main.java file looks like this:
package com.myapp;
import com.myapp.customcontrols.PackTestCC;
import com.myapp.customcontrols.PackTestModel;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URISyntaxException;
public class Main extends Application {
private MainController2 mainController;
#Override
public void start(Stage stage) throws IOException, URISyntaxException {
Font.loadFont(getClass().getResourceAsStream("Fonts/DINOTBold.otf"), 16);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("main-view2.fxml"));
mainController = new MainController2();
fxmlLoader.setController(mainController);
Parent n = fxmlLoader.load();
Scene scene = new Scene(n, 800, 600);
mainController.getAnchorPane().getChildren().add(new PackTestCC(new PackTestModel("This is for test")));
stage.setScene(scene);
stage.setMinWidth(800);
stage.setMinHeight(600);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
main-vew2.fxml is very simple, as long as it is for tests:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane
fx:id="anchorPane" prefHeight="300.0" prefWidth="300.0"
style="-fx-border-color: #111111; -fx-border-insets: 5;"
xmlns="http://javafx.com/javafx/19"
xmlns:fx="http://javafx.com/fxml/1" />
and this is MainController2 class:
package com.myapp;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController2 implements Initializable {
#FXML
private AnchorPane anchorPane;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
public AnchorPane getAnchorPane() {
return anchorPane;
}
}
The Custom Control must look like this, according to SceneBuilder UI:
but, when I run my application, all I see is only the border from main-view2.fxml:
What I'm doing wrong, what I'm missing here?

JavaFX Wrapping an editable TextFieldTableCell

I'm trying to get a TableView TextFieldTableCell to be both wrapping the text and adjusting the cell height and also be editable at the same time.
So i'm able to make it wrapped or editable, but not at the same time.
I have been following this Thread and trying about a 100 different permutations and possibilities. I'm sure it is possible, but i'm reaching full fustration quickly. So any help would be highly appreciated!
I'm using SceneBuilder and importing the handles. MainFX.fxml: -->
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wrappingEditableCellProject.Controller">
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0">
<children>
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="id" prefWidth="75.0" text="id" />
<TableColumn fx:id="name" prefWidth="75.0" text="name" />
</columns>
</TableView>
</children>
</AnchorPane>
</children>
</StackPane>
My Main class:
package wrappingEditableCellProject;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
public static void main (String[] args) {
// TODO Auto-generated method stub
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainFX.fxml"));
primaryStage.setTitle("mainFx");
primaryStage.setScene(new Scene(root, 900, 600));
primaryStage.show();
}
}
My data entry class:
package wrappingEditableCellProject;
public class TableEntry {
private int id;
private String name;
public TableEntry (int id, String name){
this.id=id;
this.name=name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
My Controller class:
package wrappingEditableCellProject;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.IntegerStringConverter;
public class Controller {
#FXML TableView<TableEntry> tableView;
#FXML TableColumn<TableEntry, Integer> id;
#FXML TableColumn<TableEntry, String> name;
private ObservableList<TableEntry> dataList = FXCollections.observableArrayList();
#SuppressWarnings({ "rawtypes", "unchecked" })
public void initialize(){
// Set editable
tableView.setEditable(true);
// Configure columns
id.setCellValueFactory(new PropertyValueFactory<>("id"));
id.setCellFactory(TextFieldTableCell.<TableEntry, Integer>forTableColumn(new IntegerStringConverter()));
id.setStyle("-fx-alignment: CENTER-LEFT;");
id.setEditable(false);
id.setSortable(false);
name.setCellValueFactory(new PropertyValueFactory<>("name"));
name.setCellFactory(WrappingTextFieldTableCell.<TableEntry>forTableColumn());
name.setStyle("-fx-alignment: CENTER-LEFT;");
name.setSortable(false);
name.setOnEditCommit(evt -> {
System.out.println("Edit comitted");
evt.getRowValue().setName(evt.getNewValue());
});
TableColumn[] tableColumns = {id,name};
tableView.getColumns().clear();
tableView.getColumns().addAll(tableColumns);
// add data to the table
dataList.clear();
dataList.add(new TableEntry(1, "Steve Upperton Stevenson"));
dataList.add(new TableEntry(2, "Peter May Parker"));
dataList.add(new TableEntry(3, "Tony Stark the machinist"));
dataList.add(new TableEntry(4, "Pepper Pots the CEO of Stark industies"));
FilteredList<TableEntry> dataFiltered = new FilteredList<>(dataList, b -> true);
SortedList<TableEntry> dataSorted = new SortedList<>(dataFiltered);
dataSorted.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(dataSorted);
}
}
Here is my custom cell class WrappingTextFieldTableCell:
package wrappingEditableCellProject;
import javafx.scene.control.Control;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.text.Text;
import javafx.util.converter.DefaultStringConverter;
public class WrappingTextFieldTableCell<S> extends TextFieldTableCell<S, String> {
private final Text cellText;
public WrappingTextFieldTableCell() {
super(new DefaultStringConverter());
setPrefHeight(Control.USE_COMPUTED_SIZE);
this.cellText = createText();
}
#Override
public void cancelEdit() {
super.cancelEdit();
setGraphic(cellText);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty() && !isEditing()) {
setGraphic(cellText);
}
}
private Text createText() {
Text text = new Text();
text.wrappingWidthProperty().bind(widthProperty());
text.textProperty().bind(itemProperty());
return text;
}
}
This solution allows me to edit the cell(I know there are easier ways for this), but the wrapping is not taking.
As mentioned i have tried 100 different ways to approach this challenge, but i think this would be the easiest to relate to for any assistance.
Thanks for any support!

Can't seem to programmatically select TextField from TableCell (TextFieldTableCell-like) when adding a row to TableView (JavaFX 8)

In JavaFX 8, I have created a custom TableCell with a TextField to get more control than with a "regular" TextFieldTableCell. What I want to achieve is to have that TextField automatically selected when an Add button is clicked (so the user doesn't have to click on that TextField or Tab to it after the Add-Record button is fired. Unfortunately, I only manage to select the row/cell but not the underlying TextField (and the startEdit() method doesn't seem to be reached).
Here is my code (Main FX Application code, POJO, FXML code created in Scene Builder, Controller code, and CustomTextFieldTableCell class):
Main.java
package test;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
POJO
package test;
import javafx.beans.property.SimpleStringProperty;
class TestObject {
private final SimpleStringProperty field1 = new SimpleStringProperty();
private final SimpleStringProperty field2 = new SimpleStringProperty();
public SimpleStringProperty field1Property() {
return field1;
}
public void setField1(String string) {
field1.set(string);
}
public SimpleStringProperty field2Property() {
return field2;
}
public void setField2(String string) {
field2.set(string);
}
}
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="425.0" prefWidth="517.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171" fx:controller="test.FXMLDocumentController">
<children>
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<TableView fx:id="tableView" layoutX="14.0" layoutY="52.0" prefHeight="359.0" prefWidth="489.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="52.0">
<columns>
<TableColumn fx:id="col1" prefWidth="150.0" text="C1" />
<TableColumn fx:id="col2" minWidth="0.0" prefWidth="141.0" text="C2" />
</columns>
</TableView>
<Button fx:id="btnAdd" layoutX="14.0" layoutY="14.0" onAction="#handleAdd" text="_Add" />
</children>
</AnchorPane>
FXMLDocumentController.java
package test;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class FXMLDocumentController implements Initializable {
#FXML
private Button btnAdd;
#FXML
private TableView<TestObject> tableView;
#FXML
private TableColumn<TestObject, String> col1;
#FXML
private TableColumn<TestObject, String> col2;
#FXML
private void handleAdd(ActionEvent event) {
TestObject testObject = new TestObject();
tableView.getItems().add(testObject);
tableView.edit(tableView.getItems().indexOf(testObject), col1);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
col1.setCellValueFactory(cellData -> cellData.getValue().field1Property());
col1.setCellFactory((final TableColumn<TestObject, String> column) -> new CustomTextFieldTableCell());
col1.setOnEditStart((TableColumn.CellEditEvent<TestObject, String> event) -> {
//Inside code doesn't seem to ever get reached
System.out.println("Edit started");
});
col2.setCellValueFactory(cellData -> cellData.getValue().field2Property());
col2.setCellFactory((final TableColumn<TestObject, String> column) -> new TableCell<>());
}
}
CustomTextFieldTableCell.java
package test;
import javafx.event.ActionEvent;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
public class CustomTextFieldTableCell extends TableCell<TestObject, String> {
private final TextField textField;
public CustomTextFieldTableCell() {
textField = new TextField();
textField.setOnAction((ActionEvent event) -> {
commitEdit(textField.getText());
event.consume();
});
textField.prefWidthProperty().bind(prefWidthProperty().subtract(3));
}
/** {#inheritDoc} */
#Override
public void startEdit() {
if (!isEditable()
|| getTableView() == null
|| getTableColumn() == null
|| getTableView() != null && !getTableView().isEditable()
|| getTableColumn() != null && !getTableColumn().isEditable()) {
return;
}
super.startEdit();
if (isEditing()) {
/*
textField.setText(getItem().trim());
this.setText(textField.getText());
*/
//Platform.runLater(() -> textField.requestFocus());
textField.requestFocus();
}
}
/** {#inheritDoc} */
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (empty) {
setGraphic(null);
} else {
textField.setText(item == null ? "" : item.trim());
setGraphic(textField);
}
}
}
What visually occurs:
What I need my code to do is to have caret placed inside the TextField or TextField focused, but this doesn't occur with my code right now.
Any idea what I am missing out?

how to add custom skin for textField in javafx using css?

I am trying to add a default skin to text Field using css but its not working as i expect it to.
I expect a right button in text Field like one's in Metro theme of Win8.
Here is fxml i am using
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="300.0" prefWidth="400.0" stylesheets="#custom.css" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<children>
<TextField layoutX="126.0" layoutY="138.0" />
</children>
</AnchorPane>
Here is css :
.text-field{
-fx-skin: "application.MetroTextFieldSkin";
}
And here are 2 skin classes i am using :
first one :
package application;
import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
/**
* Created by pedro_000 on 12/5/13.
*/
public class MetroTextFieldSkin extends TextFieldWithButtonSkin{
public MetroTextFieldSkin(TextField textField) {
super(textField);
}
protected void rightButtonPressed()
{
getSkinnable().setText("");
}
}
2nd one :
package application;
import com.sun.javafx.scene.control.behavior.TextFieldBehavior;
import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.control.Skin;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
public class TextFieldWithButtonSkin extends TextFieldSkin{
private StackPane rightButton;
private Region rightButtonGraphic;
protected TextField textField;
public TextFieldWithButtonSkin(TextField textField) {
super(textField);
this.textField = textField;
rightButton = new StackPane();
rightButton.getStyleClass().setAll("right-button");
rightButton.setFocusTraversable(false);
rightButtonGraphic = new Region();
rightButtonGraphic.getStyleClass().setAll("right-button-graphic");
rightButtonGraphic.setFocusTraversable(false);
rightButtonGraphic.setMaxWidth(Region.USE_PREF_SIZE);
rightButtonGraphic.setMaxHeight(Region.USE_PREF_SIZE);
rightButton.setVisible(false);
rightButtonGraphic.setVisible(false);
rightButton.getChildren().add(rightButtonGraphic);
getChildren().add(rightButton);
setupListeners();
}
private void setupListeners() {
final TextField textField = getSkinnable();
rightButton.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
rightButtonPressed();
}
});
rightButton.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
rightButtonReleased();
}
});
textField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
textChanged();
}
});
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
focusChanged();
}
});
}
protected void textChanged()
{
if (textField.getText() == null)
return;
System.out.println(textField.getText().isEmpty());
rightButton.setVisible(!textField.getText().isEmpty());
rightButtonGraphic.setVisible(!textField.getText().isEmpty());
}
protected void focusChanged()
{
if (textField.getText() == null)
return;
rightButton.setVisible(textField.isFocused() && !textField.getText().isEmpty());
rightButtonGraphic.setVisible(textField.isFocused() && !textField.getText().isEmpty());
}
#Override
protected void layoutChildren(double x, double y, double w, double h) {
super.layoutChildren(x, y, w, h);
final double clearGraphicWidth = snapSize(rightButtonGraphic.prefWidth(-1));
final double clearButtonWidth = rightButton.snappedLeftInset() + clearGraphicWidth + rightButton.snappedRightInset();
rightButton.resize(clearButtonWidth, h);
positionInArea(rightButton,
(x+w) - clearButtonWidth, y,
clearButtonWidth, h, 0, HPos.CENTER, VPos.CENTER);
}
protected void rightButtonPressed()
{
}
protected void rightButtonReleased()
{
}
}
Am i missing something which is necessary to make it work.
These are actualy created by pedro for his theme jMetro.

Howto bind custom property of my own component in FXML file in javafx-8?

This code work fine in javafx-2.2, but not work in javafx-8 (1.8.0-b132 from oracle downloads)
Binding of property f2.myText not work. What's wrong?
test.fxml content:
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx8test.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextField fx:id="f1" layoutX="70" text="${f2.myText}" layoutY="20" />
<MyTextField fx:id="f2" layoutX="70" layoutY="60" />
</children>
</AnchorPane>
MyTextField.java content:
package javafx8test;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
public class MyTextField extends TextField{
private StringProperty myText = new SimpleStringProperty();
public MyTextField(){
super();
textProperty().addListener(new ChangeListener<String>(){
#Override
public void changed(ObservableValue<? extends String> ov, String t, String t1) {
myText.set( "("+t1+")");
}
});
}
public StringProperty myTextProperty(){
return myText;
}
public void setMyText(String str){
myText.set(str);
}
public String getMyText(){
return myText.get();
}
}
Javafx8Probs.java content:
package javafx8test;
import java.net.URL;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class Javafx8Probs extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
URL url =Javafx8Probs.class.getResource("test.fxml");
FXMLLoader fxmlLoader = new FXMLLoader(url);
Parent root = (Parent) fxmlLoader.load();
Stage s = new Stage();
Scene scene=new Scene(root);
s.setScene(scene);
s.show();
TextField f1 = (TextField)scene.lookup("#f1");
MyTextField f2 = (MyTextField)scene.lookup("#f2");
f2.setMyText("asdasd");
}
}
That looks like a bug: you should file it at https://javafx-jira.kenai.com
The fix is to initialize your property as a fully-fledged property of the class, that provides correct values for getBean() and getName(). This is good practice anyway, but probably shouldn't be necessary for your binding to work.
private StringProperty myText = new SimpleStringProperty(this, "myText");

Resources