Update validator - javafx

I'm using this code to validate TextField for network port.
fieldNport.textProperty().addListener(new ChangeListener<String>()
{
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
{
IpAddressNameValidator.hide();
if (!newValue.matches("-?\\d+(\\.\\d+)?"))
{
MenuItem cc = new MenuItem(newValue + " is not correct network port");
cc.getStyleClass().add("validator-item");
IpAddressNameValidator.getItems().clear();
IpAddressNameValidator.getItems().add(cc);
IpAddressNameValidator.show(fieldNport, Side.RIGHT, 10, 0);
}
}
});
I noticed that the validator is not updated when I delete the old value with backspace. The only solution that I found is this IpAddressNameValidator.hide(); and then show the validator message again.
I there other way to refresh the validator message when I add or remove values? This solution works but the message is blinking when I add new values.

Every time the text changes and the regex expression matches then you are unnecessarily recreating the MenuItem etc. Rather do it like this:
fieldNport.textProperty().addListener(new ChangeListener<String>()
{
private MenuItem cc = new MenuItem();
{
cc.getStyleClass().add("validator-item");
ipAddressNameValidator.getItems().clear();
ipAddressNameValidator.getItems().add(cc);
}
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
{
if (!newValue.matches("-?\\d+(\\.\\d+)?"))
{
if ( ! ipAddressNameValidator.isShowing() )
{
ipAddressNameValidator.show(fieldNport, Side.RIGHT, 10, 0);
}
cc.setText( newValue + " is not correct network port" );
}
}
});

Related

set caretPosition to the right in a textField (javaFX)

I am developing an javaFX application where the user has several textfields to fill and edit. I want that if you enter a new textfield by jumping from another by pressing TAB the content of the textfield is not selected and also the cursor is on the right. The textfields have an event listener that detects when they receive the focus and I have been testing various methods of the API to position the cursor and deselect content when entering the textfield, for the moment, all without success.
Where is my error?
id_ip2B_tf.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) {
// 1 - don't work
id_ip2B_tf.deselect();
id_ip2B_tf.positionCaret(id_ip2B_tf.getLength());
// 2 - don't work
id_ip2B_tf.end();
}
}
Can you try wrapping the logic of setting the caret in Platform.runLater. Something like..
id_ip2B_tf.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) {
Platform.runLater(()->{
id_ip2B_tf.deselect();
id_ip2B_tf.positionCaret(id_ip2B_tf.getLength());
});
}
}
});

Shared ChangeListener VS multiple ChangeListeners? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I have several TextFields that need to perform certain actions when focus is lost, like: trimming text, comparing it to initial one, checking it and if it's valid - saving. Which way would be better to handle it? By creating one ChangeListener with switch statement and sharing it among my Textfields:
ChangeListener<Boolean> focusHandler = new ChangeListener<Boolean>() {
private String initialValue = null;
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean focus) {
ReadOnlyBooleanProperty booleanProperty = (ReadOnlyBooleanProperty) observable;
TextField textField = (TextField)booleanProperty.getBean();
if (focus) { // gained focus
initialValue = textField.getText();
} else { // lost focus
trimText(textField);
if(!textField.getText().equals(initialValue)){ //text was changed
if(textField.getText().isEmpty()){ //text was erased
switch (textField.getId()) {
case CoreConstants.AREA_SIZE_TF:
emptyAreaSize();
break;
case CoreConstants.NUMBER_OF_PEOPLE_TF:
emptyPeopleLiving();
break;
default:
//no actions
break;
}
}else{
switch (textField.getId()) {
case CoreConstants.NAME_TF:
System.out.println("Execute name code!");
break;
case CoreConstants.SURNAME_TF:
System.out.println("Execute last name code!");
break;
case CoreConstants.MAIL_TF:
System.out.println("Execute mail code!");
break;
default:
//no actions
break;
}}}}}};
nameTextField.focusedProperty().addListener(focusHandler);
surnameTextField.focusedProperty().addListener(focusHandler);
Or by creating separate ChangeListener for each of TextFields like this:
numberOfPeopleTextField.focusedProperty().addListener(new ChangeListener<Boolean>() {
private String initialValue = null;
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean focus) {
if (focus) { // gained focus
initialValue = numberOfPeopleTextField.getText();
} else { // lost focus
trimText(numberOfPeopleTextField);
if(!numberOfPeopleTextField.getText().equals(initialValue)){ //text was changed
if(numberOfPeopleTextField.getText().isEmpty()){
emptyPeopleLiving();
}else{
mailInfoUpdate("mail");
}
}
}
}
});
mailTextField.focusedProperty().addListener(new ChangeListener<Boolean>() {
private String initialValue = null;
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean focus) {
if (focus) { // gained focus
initialValue = mailTextField.getText();
} else { // lost focus
trimText(mailTextField);
if(!mailTextField.getText().equals(initialValue)){ //text was changed
mailInfoUpdate("mail");
}
}
}
});
Creating several ChangeListeners VS one shared ChangeListener what is better to use and why?
I'd go with option 3: Create a class containing the common code and use different handlers.
class FocusChangeListener implements ChangeListener<Boolean> {
private final TextField textField;
private final Consumer<? super String> changeHandler;
private String initialValue = null;
FocusChangeListener(TextField textField, Consumer<? super String> changeHandler) {
this.textField = textField;
this.changeHandler = changeHandler;
}
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean focus) {
if (focus) { // gained focus
initialValue = textField.getText();
} else { // lost focus
trimText(textField);
if(changeHandler != null && !textField.getText().equals(initialValue)) { //text was changed
changeHandler.accept(textField.getText());
}
}
}
}
numberOfPeopleTextField.focusedProperty().addListener(new FocusChangeListener(numberOfPeopleTextField, text -> {
if(text.isEmpty()){
emptyPeopleLiving();
} else{
mailInfoUpdate("mail");
}
}));
mailTextField.focusedProperty().addListener(new FocusChangeListener(mailTextField, text -> mailInfoUpdate("mail")));
If it suits your needs better, you could also replace the Consumer with a abstract method in FocusChangeListener...
Switching on the id is a bad idea since it does not seperate the concerns in addition to using magic strings. Reimplementing the whole listener is not a good idea either since it makes the code harder to maintain...

JavaFX ComboBox working with delay

So Im having Database, which contains Table with few parameters, one of those is "type" (TEXT). Im filling ComboBox with this "type" with this method:
public void loadTypefromDB()
{
types = FXCollections.observableArrayList();
try{
ResultSet rs = conn.createStatement().executeQuery("SELECT type FROM Products");
while(rs.next()){
String product = rs.getString("type");
types.add(product);
}
}
catch (SQLException e) {
e.printStackTrace();
}
choiceBox.setItems(types);
}
then I'm using this ComboBox to show all items of selected type in TableView.
public void choiceType(ActionEvent event)
{
choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
loadTypeDataFromDB(newValue.toString());
}
});
}
and here is loadTypeDataFromDB method which executes query with selected parameter
public void loadTypeDataFromDB(String type){
products = FXCollections.observableArrayList();
try {
PreparedStatement pst = conn.prepareStatement("SELECT name, kcal, protein, carb, fat FROM Products WHERE type=?");
pst.setString(1, type);
ResultSet rs = pst.executeQuery();
while(rs.next()){
products.add(new productData(rs.getString("name"), rs.getString("kcal"), rs.getString("protein"), rs.getString("carb"), rs.getString("fat")));
}
}
catch (SQLException e) {
e.printStackTrace();
}
colProduct.setCellValueFactory(new PropertyValueFactory<productData, String>("name"));
colKcal.setCellValueFactory(new PropertyValueFactory<productData, String>("kcal"));
colProtein.setCellValueFactory(new PropertyValueFactory<productData, String>("protein"));
colCarbs.setCellValueFactory(new PropertyValueFactory<productData, String>("carb"));
colFat.setCellValueFactory(new PropertyValueFactory<productData, String>("fat"));
tableProduct.setItems(null);
tableProduct.setItems(products);
}
It ALMOST works correctly. I run my app, choose one of types from ComboBox and nothing happens (TableView stays clear). Then I choose other type from this ComboBox and suddenly it shows items of this type in TableView and from now on, I can display all types I want, everything works. So it looks like first choice from ComboBox is null (I dont get any exceptions tho). After first choice everything starts to work correctly...
Your ChangeListener setup seems dubious to me, and likely the source of your problems (though, I can't know for certain without seeing more code):
public void choiceType(ActionEvent event)
{
choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
loadTypeDataFromDB(newValue.toString());
}
});
}
Where do you call this method? It takes an ActionEvent as the input; are you not setting up your listener until after you receive an event? Because that would certainly account for why you aren't seeing the first one.
Consider setting up the listener after adding the products (better still, where you create the ComboBox), and see if that helps:
public void loadTypefromDB()
{
types = FXCollections.observableArrayList();
try{
ResultSet rs = conn.createStatement().executeQuery("SELECT type FROM Products");
while(rs.next()){
String product = rs.getString("type");
types.add(product);
}
}
catch (SQLException e) {
e.printStackTrace();
}
choiceBox.setItems(types);
choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
loadTypeDataFromDB(newValue.toString());
}
});
}

How disable move focus from textField in JavaFX

Is there possibility to keep focus on textField in JavaFX?
I do validation on textField using listener.
textField.textProperty().addListener(
new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (!validate(newValue)) {
textField.setStyle("-fx-text-fill: green;");
textField.requestFocus();
} else {
textField.setStyle("-fx-text-fill: black;");
}
}
}
);
It is function which returns boolean depending on textField value validity. If value is not valid then I change text color to RED. Then I want to keep focus on invalid textField and force user to correct value.
Can it be done?
Thanks in advance.
Also use a listener for the focused property which takes back the focus, when it's moved somewhere else:
ChangeListener<Boolean> focusLossListener = (observable, wasFocused, isFocused) -> {
if (!isFocused) {
tf.requestFocus();
}
};
textField.textProperty().addListener(
new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
textField.focusedProperty().removeListener(focusLossListener);
if (!validate(newValue)) {
textField.focusedProperty().addListener(focusLossListener);
textField.setStyle("-fx-text-fill: green;");
textField.requestFocus();
} else {
textField.setStyle("-fx-text-fill: black;");
}
}
}
);

Table cell combobox - action not performed

I'm applying the below cell factory to a column.
targetEnviroment.setCellFactory(new Callback<TableColumn<DevWorkTabBench, String>, TableCell<DevWorkTabBench, String>>() {
#Override
public TableCell<DevWorkTabBench, String> call(TableColumn<DevWorkTabBench, String> param) {
TableCell<DevWorkTabBench, String> cell = new TableCell<DevWorkTabBench, String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
String status = null;
try {
status = getTableView().getItems().get(getIndex()).getObjectStatus();
} catch (IndexOutOfBoundsException ex) {
status = "";
}
if (status.equalsIgnoreCase("ReadyForDeployment")) {
ComboBox<String> comboBox = new ComboBox(environmentList);
comboBox.valueProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
commitEdit(newValue);
}
});
comboBox.setOnShown(new EventHandler<Event>() {
#Override
public void handle(Event event) {
getTableView().edit(getIndex(), getTableColumn());
getTableView().getSelectionModel().select(getIndex());
}
});
comboBox.setValue(item);
setGraphic(comboBox);
} else {
setGraphic(null);
}
if (empty) {
setGraphic(null);
}
}
};
return cell;
}
});
When I change the status to the mentioned status, I get the look of ComboBox in that particular cell but the drop down does not occur. Even after multiple clicks no action seems to be performed on the combobox. I do not get any exception other than the handled one. Other columns are editable and performing task as expected.
I have no idea what is wrong here. Can anyone please help me.
Since you are always displaying the combo box in the (non-empty) cells, you don't really need to go into "editing" mode as the standard TextFieldTableCell etc does. Your implementation is more similar to the CheckBoxTableCell, which essentially bypasses the editing mechanism. From the documentation for that class:
Note that the CheckBoxTableCell renders the CheckBox 'live', meaning
that the CheckBox is always interactive and can be directly toggled by
the user. This means that it is not necessary that the cell enter its
editing state (usually by the user double-clicking on the cell). A
side-effect of this is that the usual editing callbacks (such as on
edit commit) will not be called. If you want to be notified of
changes, it is recommended to directly observe the boolean properties
that are manipulated by the CheckBox.
So your cell implementation behaves similarly: don't invoke edit(...) (which I think is messing things up) and don't rely on the commitEdit(...), cancelEdit() etc methods (which won't work as you're not in editing state), but just update the model class directly.
I can't test, since there isn't a MCVE to work from, so this might not work directly, but it should be enough to get you started toward something that will work.
targetEnviroment.setCellFactory(new Callback<TableColumn<DevWorkTabBench, String>, TableCell<DevWorkTabBench, String>>() {
#Override
public TableCell<DevWorkTabBench, String> call(TableColumn<DevWorkTabBench, String> param) {
TableCell<DevWorkTabBench, String> cell = new TableCell<DevWorkTabBench, String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null) ;
} else {
String status = getTableView().getItems().get(getIndex()).getObjectStatus();
if (status.equalsIgnoreCase("ReadyForDeployment")) {
ComboBox<String> comboBox = new ComboBox(environmentList);
comboBox.valueProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
//commitEdit(newValue);
getTableView().getItems().get(getIndex()).setObjectStatus(newValue);
}
});
comboBox.setValue(item);
setGraphic(comboBox);
} else {
setGraphic(null);
}
}
}
};
return cell;
}
});

Resources