如何将 TornadoFX 中的文本字段限制为仅数字

How to restrict textfields in TornadoFX to numbers only

这里的问题是我想确保用户没有输入任何字符串或文本,尤其是我需要稍后将他的选择输入数据库,这样我就不会在数据库的部分,这里是代码的一部分,它是我希望使用具有受限整数(特别是金额 am 字段)的 textview 的视图。 PS:我对 JavaFX 和 TornadoFX 仍然是新手,所以希望这听起来不是一个相当愚蠢的问题。

我的代码:

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.


    }
}

您可以使用我们在TextField中添加的filterInput扩展函数,检查添加后的文本是否为int。如果不是,则拒绝最后的输入更改:

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

另一方面,您确实需要研究一下 ItemViewModel。将每个输入元素分配给一个变量并在提交时从输入值中提取值是一种反模式。如果您使用视图模型,您的代码将更清晰、更容易推理和重构。

PS:filterInput功能在即将发布的TornadoFX 1.7.15中可用,同时您可以将此扩展功能添加到您的项目中:

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

从您的示例来看,您似乎想要使用 PropertySheet which comes from ControlsFX。我在生产中使用它,它与 TornadoFX 配合得很好。

这是来自 samples 项目的示例,您可以仔细阅读。这将使您可以编辑和绑定多种类型,而不仅仅是数字:

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);
    }
}

您也可以查看 this question 了解更多信息。