How to make a textField which only accepts integers but greater than 0 - javafx

i am creating an program where the user has to enter the Number of dinnners on a Table which cant be zero , i am able to allow only integers as an input for the textField but how to exclude 0 and pop an error when user enters 0

A possibility to handle this simply use a ChangeListener for your textfield. In this posts its explained how to do it : Value Change Listener for JavaFX's TextField
For a range listener it should be sth like this:
TextField textField = new TextField();
textField.textProperty().addListener((observable, oldValue, newValue) -> {
int from = 0;
int to = 200;
if (newValue != null && !newValue.equals("")) {
try {
int number = Integer.parseInt(newValue);
if (number < from || number > to) {
throw new NumberFormatException();
}
} catch (NumberFormatException ignored) {
field.setText(oldValue);
}
}
});
This avoids the user to insert numbers bigger or smaller than you want. But its not a perfect way to do it (just written down fast).

I think this should work:
private void createListenerTextField (TextField textField, int LIMIT) {
UnaryOperator<TextFormatter.Change> integerFilter = change -> {
String newText = change.getControlNewText();
if (newText.matches("-?([1-9][1-9]*)?")) {
return change;
}
return null;
};
textField.setTextFormatter(new TextFormatter<>(new IntegerStringConverter(), null, integerFilter));
textField.lengthProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.intValue() > oldValue.intValue()) {
// Check if the new character is greater than LIMIT
if (textField.getText().length() >= LIMIT) {
// if it's LIMIT character then just setText to previous one
textField.setText(textField.getText().substring(0, LIMIT));
}
}
});
}
You can remove the LIMIT part if you want to let the user enter a huge number (I recommend to use it because the user can enter a bigint)

Related

TextField that accepts only positive numbers - JavaFX

I'm trying to create a TextField in JavaFX (using Scene Builder) that accepts only positive numbers.
I'm trying actually to make a TextField for a 'Credit Card Number' which accepts 13 - 16 numeric values, not including the minus sign at the beginning, and which can accept 0 at the beginning of the text.
Also, since it's a 'Credit Card Number' TextField, I'm looking for a way where I can insert automatic space after each 4 letters/numbers inserted to it.
Note: I know how to create a TextField that accepts only numbers but it also accepts minus sign at the beginning and doesn't accept the 0 as the first input.
Here is what I have been using so my TextField only accepts digits and it works like a charm as below,
public static void digitsTxtFld(TextField field) {
field.setTextFormatter(new TextFormatter<Integer>(change -> {
String newText = change.getControlNewText();
if (newText.matches("\\d*")) {
return change;
}
return null;
}));
}
And to set a character limit I use this,
public static void setTextLimit(TextArea textArea, int length) {
textArea.setTextFormatter(new TextFormatter<>(change -> {
String string = change.getControlNewText();
if (string.length() > length) {
textArea.positionCaret(string.length());
return change;
} else {
return null;
}
}));
}
Edit:
Apparently one cannot have both text formatters as the second one you call will replace the first and your field will only run with one at a time. So I made a joint formatter as follows:
public static void setTextLimitToDigitFld(TextField field, int length) {
field.setTextFormatter(new TextFormatter<Integer>(change -> {
String newText = change.getControlNewText();
if (newText.matches("\\d*") && newText.length() > length) {
return change;
}
return null;
}));
}

JavaFX ListChangeListener: getPermutation() not working

I use ListChangeListener to listen to changes in Tab Pane.
private final TabPane tabBar = new TabPane();
...
tabBar.getTabs().addListener(this::tabsChanged);
I'm trying to listen to tab move events with the following code:
private void tabsChanged(ListChangeListener.Change<? extends Tab> change) {
while (change.next()) {
if (change.wasPermutated()) {
for (int i = change.getFrom(); i < change.getTo(); i++) {
System.out.println(i + " -> " + change.getPermutation(i));
}
}
}
}
As JavaFX documentation says:
In order to get the new position of an element, you must call:
change.getPermutation(oldIndex). Returns: the new index of the same
element.
But in my case change.getPermutation(i) always returns just i.
For example, I have 4 tabs.
Their indexes are: 0, 1, 2, 3.
Then I move the 4th tab to the first position.
I expect the following output:
0 -> 1
1 -> 2
2 -> 3
3 -> 0
But I get:
0 -> 0
1 -> 1
2 -> 2
3 -> 3
How can I make it work as I need?
As already noted in the comments: the behavior you observe is a bug just reported as JDK-8278062 - the doc and your expectation based on the doc is correct, the notification (implemented in the internal class TabObservableList) is wrong.
Normally, if we want to find the newIndex, a listChangeListener would do something like:
for (int oldIndex = c.getFrom(); oldIndex < c.getTo(); ++oldIndex) {
int newIndex = c.getPermutation(oldIndex);
...
}
To work around the issue, we could manually keep a copy of the tabs, lookup the tab at the old index and find its new index in the re-ordered tabs:
for (int oldIndex = c.getFrom(); oldIndex < c.getTo(); ++oldIndex) {
Tab tab = copy.get(oldIndex);
int newIndex = c.getList().indexOf(tab);
...
}
// update the copy
Or we could have some fun and implement a TransformationList around the original tabs that does the work for us :) It jumps in when it detects a permutation and fires the correct notification. Note that the only internal class used below is SourceChangeAdapter, we either need to relax encapsulation or c&p its content (it is doing nothing but pass on notifications on behalf of the wrapper)
public class TabObservableListWrapper extends TransformationList<Tab, Tab> {
// copy of source used to build the correct permutation
private ObservableList<Tab> copy = FXCollections.observableArrayList();
public TabObservableListWrapper(ObservableList<Tab> source) {
super(source);
updateCopy();
}
#Override
protected void sourceChanged(Change<? extends Tab> c) {
// TBD: cope with a change that has
// - a mixture of permutation and other subchanges
// - multiple subchanges of type permutation
boolean isPermutation = false;
// check if the change is a permutation
while (c.next()) {
if (c.wasPermutated()) {
isPermutation = true;
break;
}
}
c.reset();
if (isPermutation) {
beginChange();
updatePermutation(c);
endChange();
} else {
// assuming other change type notifications are correct, just delegate
fireChange(new SourceAdapterChange<>(this, c));
}
// keep copy sync'ed to source
updateCopy();
}
/**
* Converts the incorrect permutation notification from source
* into a correct one and let super fire the appropriate change.
*
* Note: this method must be called inside a begin/endChange block.
* #param c a change with a single subChange of type wasPermutated
*/
private void updatePermutation(Change<? extends Tab> c) {
c.next();
int from = c.getFrom();
int to = c.getTo();
int permSize = to - from;
int[] perm = new int[permSize];
// fill the perm
for(int i = 0; i < permSize; i++) {
int oldIndex = from + i;
Tab tab = copy.get(oldIndex);
perm[i] = c.getList().indexOf(tab);
}
nextPermutation(from, to, perm);
}
// keep copy sync'ed
private void updateCopy() {
copy.setAll(getSource());
}
// implement public methods by delegating 1:1 to source
#Override
public int getSourceIndex(int index) {
return index;
}
#Override
public int getViewIndex(int index) {
return index;
}
#Override
public Tab get(int index) {
return getSource().get(index);
}
#Override
public int size() {
return getSource().size();
}
}
To use, wrap it around a tabPane's tab list and listen to the wrapper instead of directly to original list, something like:
TabObservableListWrapper wrapper = new TabObservableListWrapper(tabPane.getTabs());
wrapper.addListener((ListChangeListener<Tab>)change -> {
while (change.next()) {
if (change.wasPermutated()) {
System.out.println("from wrapper:");
for (int oldIndex = change.getFrom(); oldIndex < change.getTo(); oldIndex++) {
System.out.println(oldIndex + " -> " + change.getPermutation(oldIndex));
}
}
}
});

Javafx Textfield: Accept only digits of length 8 or 11 ( phone numbers)

Working on a project with javafx and I'm having a minor hitch. I want my textfield to accept only digits, 8 or 11 in length. Here's my code:
if(!txtPhone.getText().matches(.....) && (txtPhone.getText().length != 8 || txtPhone.getText(). length != 11){
System.out.print("Please enter a valid phone number");
}
Regular Expression can be used to create custom validations.
if (txtPhone.getText().matches("\\d{8}|\\d{11}") {
System.out.println("Its Valid Number");
//return true;
}else {
System.out.println("Invalid Input..!");
//return false;
}
You can learn and check about Regular Expressions Here
The task involves two stages:
You must first create a text box that accepts digits only (up to 11 maximum).
Second, you have to customize the user input according to your criteria (8 or 11 digits)
TextFormatter is used to solve the problem. A UnaryOperator must be passed to it to filter user input only by numbers and StringConverter to validate user input.
This is an example implementation:
UnaryOperator<TextFormatter.Change> filter = change -> {
if(change.getControlNewText().matches("\\d{0,11}")) {
return change;
}
return null;
};
StringConverter<String> converter = new StringConverter<String>() {
#Override
public String toString(String s) {
if(s == null || s.isBlank()) return "";
if(s.matches("\\d{8}|\\d{11}")) {
return s;
}
return "";
}
#Override
public String fromString(String s) {
if(s == null || s.isBlank()) return "";
if(s.matches("\\d{8}|\\d{11}")) {
return s;
}
throw new RuntimeException("Converter error");
}
};
textField.setTextFormatter(new TextFormatter<>(converter, null, filter));

bindings : count number of true booleanproperty in an observable list

i have this TableView of tasks that has a column of checkboxes. i've managed to extract the column values using stream().map(). i want to count the true values in that list.
ObservableList<BooleanProperty> list = FXCollections.observableArrayList(tasksTable.getItems().stream().map(t -> t.completedProperty()).collect(Collectors.toList()));
and another integer property
SimpleIntegerProperty count = new SimpleIntegerProperty(0);
i want this count value to be updated to the total number of true values in the list. how can i do this. i tried binding it like this
IntegerBinding count = Bindings.createIntegerBinding(() -> {
return (int)list.stream().filter(done -> done.get()).count();
}, list);
and added a listener to monitor for changes.
count.addListener((o, oldValue, newValue) -> {
System.out.println('value changed ' + newValue);
});
but its not working... nothing gets printed when i click on any checkbox...
You binding doesn't update, if the BooleanPropertys in the list change, only when the list itself is modified. You can specify conditions that trigger update changes using the correct observableArrayList method.
Example
// update triggers every time a BooleanProperty in the list is changed
ObservableList<BooleanProperty> list = FXCollections.observableArrayList((Callback<BooleanProperty, Observable[]>) e -> new Observable[] {e});
list.add(new SimpleBooleanProperty(false));
IntegerBinding trueNum = Bindings.createIntegerBinding(() -> (int) list.stream().map(BooleanProperty::get).filter(b -> b).count(), list);
trueNum.addListener((a, b, c) -> {
System.out.println(c);
});
System.out.println(trueNum.get());
list.get(0).set(true);
list.add(new SimpleBooleanProperty(false));
list.add(new SimpleBooleanProperty(true));
list.get(2).set(false);
The output is
0
1
2
1
This has the drawback of reevaluating the whole list every time one of the properties changes or the list is modified. You can do this more efficiently, if you use a ListChangeListener and register change listeners to all of the properties contained in the list:
ObservableList<BooleanProperty> list = FXCollections.observableArrayList();
...
SimpleIntegerProperty count = new SimpleIntegerProperty();
ChangeListener<Boolean> changeListener = (observable, oldValue, newValue) -> {
// increment or decrement if value was changed to true or false respecively
count.set(count.get()+ (newValue ? 1 : -1));
};
// get initial value and register change listeners to elements of list
int currentCount = 0;
for (BooleanProperty p : list) {
if (p.get()) {
currentCount++;
}
p.addListener(changeListener);
}
count.set(currentCount);
list.addListener((ListChangeListener.Change<? extends BooleanProperty> c) -> {
int modification = 0;
while (c.next()) {
// remove listeners from all properties removed in change
// and calculate update of value
for (BooleanProperty p : c.getRemoved()) {
p.removeListener(changeListener);
if (p.getValue()) {
modification--;
}
}
// add listeners from all properties added in change
// and calculate update of value
for (BooleanProperty p : c.getAddedSubList()) {
p.addListener(changeListener);
if (p.getValue()) {
modification++;
}
}
}
// update count
count.set(count.get()+modification);
});
Your lambda is called only once. You specify dependency list but uses tasksTable.getItems() In lambda-extractor you should use only values you specify as dependencies.
Also take a look at EasyBind library.

JavaFX8: How to create listener for selection of row in Tableview?

I currently have two tableviews in one screen, which results in both TableViews have rows which the user can select.
Now I want only one row to be selected at the same time (doesn't matter which TableView it is selected from). I was thinking about some kind of listener which deselects the other row when a row is selected. This is my initial setup:
Step 1
Search for a way to bind a method to the selection of a row (there is not something like tableview.setOnRowSelected(method))
Step 2
Create the method which acts like a kind of listener: when a row is selected, deselect the other row (I know how to do this part)
Class1 selectedObject1 = (Class1)tableview1.getSelectionModel().getSelectedItem();
Class2 selectedObject2 = (Class2)tableview2.getSelectionModel().getSelectedItem();
if(selectedObject1 != null && selectedObject2 != null) {
tableview1.getSelectionModel().clearSelection();
}
So, step one is the problem. I was thinking of an observable list on which a listener can be created, and then add the selected row to the list. When this happens, the listener can call the method.
Anyone any clue how to make this?
Any help is greatly appreciated.
The selectedItem in the selection model is an observable property, so you should be able to achieve this with:
tableview1.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if (newSelection != null) {
tableview2.getSelectionModel().clearSelection();
}
});
tableview2.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if (newSelection != null) {
tableview1.getSelectionModel().clearSelection();
}
});
My solution would be creating custom cell factory for table and set it for each table columns.
Callback<TableColumn<..., ...>, TableCell<..., ...>> value = param -> {
TextFieldTableCell cell = new TextFieldTableCell<>();
cell.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> {
//your code
}
);
return cell;
};
packageName.setCellFactory(value);
table1.column1.setCellFactory();
table2.column1.setCellFactory();
...
I use it for deleting the chosen row.
public void ButtonClicked()
{
ObservableList<Names> row , allRows;
allRows = table.getItems();
row = table.getSelectionModel().getSelectedItems();
row.forEach(allRows::remove);
}
This question helped me but during experiment in javafx and jfoenix this also works for me.
deleteSingle.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
StringProperty selectedItem = table.getSelectionModel().getSelectedItem().getValue().link1;
System.out.println("That is selected item : "+selectedItem);
if (selectedItem.equals(null)) {
System.out.println(" No item selected");
} else {
System.out.println("Index to be deleted:" + selectedItem.getValue());
//Here was my database data retrieving and selectd
// item deleted and then table refresh
table.refresh();
return;
}
});
In case you need not only the row, but the x|y position of the table cell, do this:
table.getFocusModel().focusedCellProperty().addListener(
new ChangeListener<TablePosition>() {
#Override
public void changed(ObservableValue<? extends TablePosition> observable,
TablePosition oldPos, TablePosition pos) {
int row = pos.getRow();
int column = pos.getColumn();
String selectedValue = "";
if (table.getItems().size() > row
&& table.getItems().get(row).size() > column) {
selectedValue = table.getItems().get(row).get(column);
}
label.setText(selectedValue);
}
});
In this example, I am using a "classic" TableView with List<String> as column model. And, of course, that label is just an example from my code.

Resources