JavaFX如何计算键入错误

JavaFX如何计算键入错误,java,javafx,Java,Javafx,我正试图让我的第一个应用程序遇到障碍。该应用程序基本上只是一个简单的打字练习应用程序,用户可以得到一个他们复制的字符串。我正在尝试实现一个计数,它统计用户所犯错误的数量 目前,我有一个代码,它使用一个监听器来观察用户输入到文本区域的字符串。每次用户字符串不等于提供的字符串时,我都会添加一个错误计数,问题是我只想为每个错误的计数添加1。例如,当前,如果您犯了一个错误并键入了2个错误的字符,那么错误计数将上升到3,因为每次按下一个键时代码都会运行,这意味着它会对2个错误字符和1个退格进行计数以删除它

我正试图让我的第一个应用程序遇到障碍。该应用程序基本上只是一个简单的打字练习应用程序,用户可以得到一个他们复制的字符串。我正在尝试实现一个计数,它统计用户所犯错误的数量

目前,我有一个代码,它使用一个监听器来观察用户输入到文本区域的字符串。每次用户字符串不等于提供的字符串时,我都会添加一个错误计数,问题是我只想为每个错误的计数添加1。例如,当前,如果您犯了一个错误并键入了2个错误的字符,那么错误计数将上升到3,因为每次按下一个键时代码都会运行,这意味着它会对2个错误字符和1个退格进行计数以删除它们,我希望这只会将1添加到错误计数中

我目前拥有的代码如下:

public class MainController implements Initializable {

    @FXML
    private BorderPane errorStatus;
    @FXML
    private TextArea inputTextArea;
    @FXML
    public TextArea generatedText;

    private String userText;
    private String thePassage;
    private Integer errorCount = 0;
    private Boolean errorCheck = false;

    timer time = new timer();

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        thePassage = PassageData.getPassage();
        generatedText.setText(thePassage);

        inputTextArea.textProperty().addListener(new ChangeListener<String>() {

            @Override
            public void changed(ObservableValue<? extends String> observable, 
            String oldValue, String newValue) {
            if (!inputTextArea.getText().isEmpty()) {
                time.start();
            }

            userText = newValue;

            if (userText.equals("") || userText.equals(null)) {
                errorStatus.setStyle(
                        "-fx-background-color: radial-gradient(radius 100%, white, white); -fx-background-radius: 10; -fx-border-radius: 10");
            } else if (thePassage.regionMatches(0, userText, 0, userText.length())) {
                errorCheck = false;
                errorStatus.setStyle(
                        "-fx-background-color: radial-gradient(radius 100%, green, white); -fx-background-radius: 10; -fx-border-radius: 10");
            } else {
                errorCheck = true;
                errorStatus.setStyle(
                        "-fx-background-color: radial-gradient(radius 100%, red, white); -fx-background-radius: 10; -fx-border-radius: 10");
            }

            if (userText.equals(thePassage)) {
                thePassage = PassageData.getPassage();
                generatedText.setText(thePassage);
                Platform.runLater(() -> {
                    inputTextArea.clear();
                });
                errorStatus.setStyle(
                        "-fx-background-color: radial-gradient(radius 100%, white, white); -fx-background-radius: 10; -fx-border-radius: 10");
                time.pause();
            }

            if (errorCheck) {
                errorCount++;
                System.out.println("Error count = " + errorCount);
            }
        }
    });
}

}

您需要为TextArea设置一个更改侦听器,然后将输入字符串的每个字符与输入文本的每个字符进行比较

下面的MCVE演示了这一点:

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        VBox root = new VBox(5);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        IntegerProperty errorCount = new SimpleIntegerProperty(0);

        String target = "This is the sample text to be typed correctly.";
        Label instructions = new Label(target);

        TextArea textArea = new TextArea();
        textArea.setWrapText(true);

        HBox hbox = new HBox(5);
        hbox.setAlignment(Pos.CENTER);

        Label errorsLabel = new Label();
        hbox.getChildren().addAll(new Label("Errors:"), errorsLabel);

        // Bind the label to errorcount
        errorsLabel.textProperty().bind(errorCount.asString());

        // Listen for changes to the textArea text and check again target string
        textArea.textProperty().addListener((observableValue, s, newValue) -> {
            if (newValue != null) {
                errorCount.set(getErrorCount(target, newValue));
            }
        });

        root.getChildren().addAll(instructions, textArea, hbox);
        primaryStage.setScene(new Scene(root));

        primaryStage.show();
    }

    private int getErrorCount(String target, String entered) {

        int errors = 0;

        // Compare each character in the strings
        char[] targetChars = target.toCharArray();
        char[] enteredChars = entered.toCharArray();

        // Starting at the beginning of the entered text, check that each character, in order, matches the target String
        for (int i = 0; i < enteredChars.length; i++) {
            if (enteredChars[i] != targetChars[i]) {
                errors++;
            }
        }

        return errors;
    }
}
因此,每次在TextArea中键入或删除字符时,getErrorCount方法都会将输入的文本与目标字符串进行比较。如果任何字符不正确,将增加错误计数


这与上面评论中的提交按钮非常相似,但每次文本区域中的文本更改时都会执行此操作,而不需要额外的按钮。

您需要为文本区域设置一个更改侦听器,然后将输入字符串的每个字符与输入文本的每个字符进行比较

下面的MCVE演示了这一点:

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        VBox root = new VBox(5);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        IntegerProperty errorCount = new SimpleIntegerProperty(0);

        String target = "This is the sample text to be typed correctly.";
        Label instructions = new Label(target);

        TextArea textArea = new TextArea();
        textArea.setWrapText(true);

        HBox hbox = new HBox(5);
        hbox.setAlignment(Pos.CENTER);

        Label errorsLabel = new Label();
        hbox.getChildren().addAll(new Label("Errors:"), errorsLabel);

        // Bind the label to errorcount
        errorsLabel.textProperty().bind(errorCount.asString());

        // Listen for changes to the textArea text and check again target string
        textArea.textProperty().addListener((observableValue, s, newValue) -> {
            if (newValue != null) {
                errorCount.set(getErrorCount(target, newValue));
            }
        });

        root.getChildren().addAll(instructions, textArea, hbox);
        primaryStage.setScene(new Scene(root));

        primaryStage.show();
    }

    private int getErrorCount(String target, String entered) {

        int errors = 0;

        // Compare each character in the strings
        char[] targetChars = target.toCharArray();
        char[] enteredChars = entered.toCharArray();

        // Starting at the beginning of the entered text, check that each character, in order, matches the target String
        for (int i = 0; i < enteredChars.length; i++) {
            if (enteredChars[i] != targetChars[i]) {
                errors++;
            }
        }

        return errors;
    }
}
因此,每次在TextArea中键入或删除字符时,getErrorCount方法都会将输入的文本与目标字符串进行比较。如果任何字符不正确,将增加错误计数


这与上面评论中的Submit按钮想法非常相似,但每次文本区域中的文本更改时都会执行,而不需要额外的按钮。

如果框架提供更高级别的支持,重复几个问题时不要使用低级侦听器

在此上下文中,对文本输入的细粒度更改的高级别支持是一个重要的特性,特别是它的过滤器属性。当文本以任何方式(包括插入符号导航)更改时,都会通知这样的过滤器,甚至允许修改更改-所有这些都是在textProperty更改之前进行的

将根据给定文本计算错误的原始代码段-有关上下文,请参阅


如果框架提供了更高级别的支持,那么重复几个问题不要使用低级侦听器

在此上下文中,对文本输入的细粒度更改的高级别支持是一个重要的特性,特别是它的过滤器属性。当文本以任何方式(包括插入符号导航)更改时,都会通知这样的过滤器,甚至允许修改更改-所有这些都是在textProperty更改之前进行的

将根据给定文本计算错误的原始代码段-有关上下文,请参阅


您刚刚发现了几乎没有应用程序在用户输入时执行验证的原因。等待用户输入完毕后再进行验证。最明显的方法是有一个按钮,上面有“提交”或类似的文本。另一个不太明显的方法是设置文本字段的,因此只有当用户按Enter键时才进行验证。我考虑过这样做,但如果我正确理解了这一点,我想在用户出现错误时警告用户,以便他们可以在键入时进行更正。如果我使用了submit之类的按钮,那么我将无法执行此操作,或者我遗漏了什么?我基本上是在尝试制作与工作原理非常相似的东西。使用TextFormatter:在其筛选器中,您可以执行任何您想要的操作,f.i.计算新输入中的错误并忽略清理中的更改effort@VGR可能存在而且实际上存在这样的上下文,即提交验证是正确的操作,但也存在我们希望键入验证的上下文。。。在fx中,使用TextFormatter很容易做到这一点:我们可以选择是直接干预并拒绝更改,还是只添加一些错误标记,或者做我们需要做的任何事情:您刚刚发现了几乎没有应用程序在用户输入时执行验证的原因。等待用户输入完毕后再进行验证。最明显的方法是有一个按钮,上面有“提交”或类似的文本。另一个不太明显的方法是设置文本字段的,因此只有当用户按Enter键时才进行验证。我考虑过这样做,但如果我正确理解了这一点,我想在用户出现错误时警告用户,以便他们可以在键入时进行更正。如果我使用了一个按钮,比如submit,那么我就不能这样做,或者我遗漏了什么?我基本上是想做一些与h非常相似的东西
使用TextFormatter:在它的过滤器中,你可以做任何你想做的事情,f.i.计算新输入中的错误并忽略清理中的更改effort@VGR可能存在而且实际上存在这样的上下文,即提交验证是正确的操作,但也存在我们希望键入验证的上下文。。。在fx中,使用TextFormatter很容易做到这一点:我们可以选择是直接干预并拒绝更改,还是只添加一些错误标记,或者做我们需要做的任何事情:感谢mcve:尽管您的方法不太理想:始终使用可用的最高抽象,这里有一个TextFormatter谢谢你的mcve:虽然你的方法不太理想:总是追求可用的最高抽象,这里有一个TextFormatter谢谢你,这几乎正是我想要的。现在唯一的问题是,当用户开始出错时,我只希望它在错误中添加1。假设他们在一行中输入了3个错误字符,那么错误计数中只会添加1个字符。你对怎么做有什么建议吗?这是很简单的逻辑。。。你所需要的只是一点机会的记录和计数。。。留给你谢谢,这几乎正是我想要的。现在唯一的问题是,当用户开始出错时,我只希望它在错误中添加1。假设他们在一行中输入了3个错误字符,那么错误计数中只会添加1个字符。你对怎么做有什么建议吗?这是很简单的逻辑。。。你所需要的只是一点机会的记录和计数。。。留给你