简体   繁体   中英

How to restrict textfields in TornadoFX to numbers only

The problem here is that I wanna make sure that the user doesn't enter any strings or text especially that I need to enter his choice into a database later so I don't things to get messed up in the database's part, here is part of code which is the view I wish to use the textview with restricted Integers (specifically the amount am field). PS: I'm still new to both JavaFX and TornadoFX so hope this doesn't sound like a rather silly question.

My Code:

package com.company.view

import javafx.beans.property.SimpleIntegerProperty
import javafx.scene.control.CheckBox
import tornadofx.*
import javafx.scene.control.TextField
import javafx.util.converter.NumberStringConverter
import java.sql.Connection

class Add: View() {
    override val root = Form()
    private val mainMenu: MainMenu by inject()
    private var cname: TextField by singleAssign()
    private var address: TextField by singleAssign()
    private var sname: TextField by singleAssign()
    private var ch: CheckBox by singleAssign()
    private var am: TextField by singleAssign()
    var conn: Connection?= mainMenu.conn

    init {
        with(root) {
            vbox(30.0) {
                fieldset("Enter Your Info below") {
                    field("Enter The Customer's Name") {
                            cname = textfield()
                    }
                    field("Enter the Customer's address") {
                        address = textfield()
                    }
                    field("Enter Bought Stock's Name") {
                        sname = textfield()
                    }
                    field("Do you wish to pay now?") {
                        ch = checkbox()
                    }
                    field("Enter the amount you wish to buy"){
                        am = textfield()
                    }
                    button("Submit")
                    {
                        setOnAction {
                            addPayment(cname.text, address.text, sname.text, ch.isSelected, am.text)
                        }
                    }
                }
            }
        }
    }

   private fun addPayment(cusName: String, caddress: String, stname: String, che: Boolean,am: String){
//required code for inserting into the database here.


    }
}

You can use the filterInput extension function we've added to TextField and check that the text after the addition is in int. If it's not, deny the last input change:

textfield {
    filterInput { it.controlNewText.isInt() } 
}

On another note, you really need to look into ItemViewModel. It's an anti-pattern to assign each input element to a variable and extract the values from the input values on submit. Your code will be a lot cleaner and easier to reason about and refactor later if you use view models.

PS: The filterInput function is available in the soon to be released TornadoFX 1.7.15, in the mean time you can add this extension function to your project:

fun TextInputControl.filterInput(discriminator: (TextFormatter.Change) -> Boolean) {
    textFormatter = TextFormatter<Any>(CustomTextFilter(discriminator))
}

From your example it seems like that you'd want to use a PropertySheet which comes from ControlsFX . I use it in production and it works well with TornadoFX.

Here is an example from the samples project which you can peruse. This will let you edit and bind multiple types not just numbers:

public class PropertySheetExample extends VBox {
    private static Map<String, Object> customDataMap = new LinkedHashMap<>();
    static {
        customDataMap.put("Group 1#My Text", "Same text"); // Creates a TextField in property sheet
        customDataMap.put("Group 1#My Date", LocalDate.of(2000, Month.JANUARY, 1)); // Creates a DatePicker
        customDataMap.put("Group 2#My Enum Choice", SomeEnumType.EnumValue); // Creates a ChoiceBox
        customDataMap.put("Group 2#My Boolean", false); // Creates a CheckBox
        customDataMap.put("Group 2#My Number", 500); // Creates a NumericField
    }

    class CustomPropertyItem implements PropertySheet.Item {
        private String key;
        private String category, name;

        public CustomPropertyItem(String key) {
            this.key = key;
            String[] skey = key.split("#");
            category = skey[0];
            name = skey[1];
        }

        @Override
        public Class<?> getType() {
            return customDataMap.get(key).getClass();
        }

        @Override
        public String getCategory() {
            return category;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String getDescription() {
            return null;
        }

        @Override
        public Object getValue() {
            return customDataMap.get(key);
        }

        @Override
        public void setValue(Object value) {
            customDataMap.put(key, value);
        }
    }

    public PropertySheetExample {
        ObservableList<PropertySheet.Item> list = FXCollections.observableArrayList();
        for (String key : customDataMap.keySet())
            list.add(new CustomPropertyItem(key));

        PropertySheet propertySheet = new PropertySheet(list);
        VBox.setVgrow(propertySheet, Priority.ALWAYS);
        getChildren().add(propertySheet);
    }
}

You can also take a look at this question for more info.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM