由于插入符号位置,文本字段内出现 Javafx indexOutOfBoundsException

发布于 2025-01-11 10:55:09 字数 3240 浏览 0 评论 0原文

我正在构建一个小型应用程序,其中通过屏幕上的按钮更新或删除 TextField 文本。我已经利用了这篇帖子 能够移动插入符号并添加文本。我可以在 TextField 中添加和删除字符,但是当向 TextField 添加 n 个字符时,则 n数量被删除 当您尝试添加另一个字符时,会发生 IndexOutOfBoundsException ,因为插入符位置(当所有字符都被删除时)在它应该是 0 的时候变成 1。我不知道为什么它在它应该是 1 的时候变成 1是 0。我做错了什么 这里?

import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
            
            BorderPane root = new BorderPane();
            Pane panel = new Pane();
            VBox box = new VBox();
            TextField tf = new TextField();
            Button characterButton = new Button("a");
            Button deleteChar = new Button("delete");
            
            box.getChildren().addAll(tf, characterButton, deleteChar );
            panel.getChildren().add(box);
            root.getChildren().add(panel);
            
            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
            
            //handle caret pos
            AtomicInteger caretPos = new AtomicInteger();
            tf.caretPositionProperty().addListener((obs, oldVal, newVal) -> {
                System.out.println("newval" + newVal);
                if (tf.isFocused()) {
                    caretPos.set(newVal.intValue());
                    System.out.println("Innernewval" + newVal);
                }
            });
            //add character
            characterButton.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int pos = caretPos.get();
                tf.insertText(pos, btn.getText());
                tf.requestFocus();
                tf.positionCaret(pos+1);
                System.out.println("caretPos on add: " + caretPos.get());

            });
            //remove character
            deleteChar.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int newCaretPos = caretPos.get()-1;
                tf.deleteText(newCaretPos, caretPos.get());
                tf.requestFocus();
                tf.positionCaret(newCaretPos);   
                System.out.println("caretPos on delete: " + caretPos.get());
            });
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

I'm building a small app where TextField text is updated or deleted via buttons on screen. I have utilised code from this post to be able to move the caret around and add text. I can add and delete characters within the TextField however when n amount of characters are added to the TextField then n amount are removed an IndexOutOfBoundsException occurs when you attempt to add another character as the caret position (when all characters are removed) becomes 1 when it should be 0. I do not know why it becomes 1 when it should be 0. What have I done wrong here?

import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
            
            BorderPane root = new BorderPane();
            Pane panel = new Pane();
            VBox box = new VBox();
            TextField tf = new TextField();
            Button characterButton = new Button("a");
            Button deleteChar = new Button("delete");
            
            box.getChildren().addAll(tf, characterButton, deleteChar );
            panel.getChildren().add(box);
            root.getChildren().add(panel);
            
            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
            
            //handle caret pos
            AtomicInteger caretPos = new AtomicInteger();
            tf.caretPositionProperty().addListener((obs, oldVal, newVal) -> {
                System.out.println("newval" + newVal);
                if (tf.isFocused()) {
                    caretPos.set(newVal.intValue());
                    System.out.println("Innernewval" + newVal);
                }
            });
            //add character
            characterButton.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int pos = caretPos.get();
                tf.insertText(pos, btn.getText());
                tf.requestFocus();
                tf.positionCaret(pos+1);
                System.out.println("caretPos on add: " + caretPos.get());

            });
            //remove character
            deleteChar.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int newCaretPos = caretPos.get()-1;
                tf.deleteText(newCaretPos, caretPos.get());
                tf.requestFocus();
                tf.positionCaret(newCaretPos);   
                System.out.println("caretPos on delete: " + caretPos.get());
            });
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如若梦似彩虹 2025-01-18 10:55:10

您的代码无法编译。您有一个catch,但没有try。在下面的代码中,我删除了 [orphan] catch 块。另外,您的样式表,即文件application.css,与您的问题无关,因此为了使问题中的代码成为最小的、可重现的示例 我建议您删除该部分。它在下面的代码中被注释掉了。

caretPos 为零并且按下 deleteChar 按钮时,我只会收到 IndexOutOfBoundsException 。因此,您只需添加处理边缘情况的代码。在下面的代码中,请参阅注释后的部分当'caretPos'为零时处理删除。

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
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) throws Exception {
        BorderPane root = new BorderPane();
        Pane panel = new Pane();
        VBox box = new VBox();
        TextField tf = new TextField();
        Button characterButton = new Button("a");
        Button deleteChar = new Button("delete");

        box.getChildren().addAll(tf, characterButton, deleteChar);
        panel.getChildren().add(box);
        root.getChildren().add(panel);

        Scene scene = new Scene(root, 400, 400);
//        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();

        // handle caret pos
        AtomicInteger caretPos = new AtomicInteger();
        tf.caretPositionProperty().addListener((obs, oldVal, newVal) -> {
            System.out.println("newval: " + newVal);
            if (tf.isFocused()) {
                caretPos.set(newVal.intValue());
                System.out.println("Innernewval: " + newVal);
            }
        });
        // add character
        characterButton.setOnAction((event) -> {
            Button btn = (Button) event.getSource();
            System.out.println("Pressed " + btn.getText() + " button");
            int pos = caretPos.get();
            tf.insertText(pos, btn.getText());
            tf.requestFocus();
            tf.positionCaret(pos + 1);
            System.out.println("caretPos on add: " + caretPos.get());

        });
        // remove character
        deleteChar.setOnAction((event) -> {
            Button btn = (Button) event.getSource();
            System.out.println("Pressed " + btn.getText() + " button");

            // Handle delete when 'caretPos' is zero.
            if (caretPos.get() == 0) {
                if (tf.getText().isEmpty()) {
                    return; // Nothing to delete.
                }
                else {
                    caretPos.set(1); // Ensure 'newCaretPos' will not be negative.
                }
            }

            int newCaretPos = caretPos.get() - 1;
            tf.deleteText(newCaretPos, caretPos.get());
            tf.requestFocus();
            tf.positionCaret(newCaretPos);
            caretPos.set(newCaretPos);
            System.out.println("caretPos on delete: " + caretPos.get());
        });
    }
}

编辑

你是对的。当我使用 JavaFX 8 运行您的代码时,我确实重现了该问题。经过一些调试后,问题是当 TextField 包含单个字符并且您按 deleteChar 时,caretPositionProperty 侦听器不会运行,因此 < code>caretPosition 更新,并保持值 1(一)而不是 0(零)。

这个问题可能有很多解决方法。我选择在事件处理程序中的 System.out.println("caretPos on delete: " + caretPos.get()); 行之后添加以下 if 语句deleteChar

if (tf.getText().isEmpty()) {
    caretPos.set(0);
}

为了完整起见,这里是我用来调试程序的代码。

import java.util.concurrent.atomic.AtomicInteger;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            
            BorderPane root = new BorderPane();
            Pane panel = new Pane();
            VBox box = new VBox();
            TextField tf = new TextField();
            Button characterButton = new Button("a");
            Button deleteChar = new Button("delete");
            
            box.getChildren().addAll(tf, characterButton, deleteChar );
            panel.getChildren().add(box);
            root.getChildren().add(panel);
            
            Scene scene = new Scene(root,400,400);
//            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
            
            //handle caret pos
            AtomicInteger caretPos = new AtomicInteger();
            tf.caretPositionProperty().addListener((obs, oldVal, newVal) -> {
                System.out.println("newval" + newVal);
                if (tf.isFocused()) {
                    caretPos.set(newVal.intValue());
                    System.out.println("Innernewval" + newVal);
                }
            });
            //add character
            characterButton.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int pos = caretPos.get();
                System.out.println("###  DBUG  ### -> Adding: [Before 'insertText'] pos = " + pos);
                tf.insertText(pos, btn.getText());
                System.out.println("###  DBUG  ### -> Adding: [Before 'requestFocus'] pos = " + pos);
                tf.requestFocus();
                System.out.println("###  DBUG  ### -> Adding: [Before 'positionCaret'] pos = " + pos);
                tf.positionCaret(pos+1);
                System.out.println("caretPos on add: " + caretPos.get());
            });
            //remove character
            deleteChar.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int newCaretPos = caretPos.get()-1;
                System.out.println("###  DBUG  ### -> Deleting: [Before 'deleteText'] newCaretPos = " + newCaretPos);
                tf.deleteText(newCaretPos, caretPos.get());
                System.out.println("###  DBUG  ### -> Deleting: [Before 'requestFocus'] newCaretPos = " + newCaretPos);
                tf.requestFocus();
                System.out.println("###  DBUG  ### -> Deleting: [Before 'positionCaret'] newCaretPos = " + newCaretPos);
                tf.positionCaret(newCaretPos);   
                System.out.println("caretPos on delete: " + caretPos.get());
                if (tf.getText().isEmpty()) {
                    caretPos.set(0);
                }
            });
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

这是当 TextField 包含单个字符并且我按 deleteChar 时的输出。

newval0
Pressed delete button
###  DBUG  ### -> Deleting: [Before 'deleteText'] newCaretPos = 0
###  DBUG  ### -> Deleting: [Before 'requestFocus'] newCaretPos = 0
###  DBUG  ### -> Deleting: [Before 'positionCaret'] newCaretPos = 0
caretPos on delete: 1

如您所见,caretPositionProperty 侦听器未执行。

Your code does not compile. You have a catch without a try. In the below code, I removed the [orphan] catch block. Also, your style sheet, i.e. file application.css, is not related to your problem so in order to make the code in your question a minimal, reproducible example I suggest that you remove that part. It is commented out in the below code.

I only get IndexOutOfBoundsException when caretPos is zero and I press deleteChar button. Hence you simply need to add code that handles that edge case. In the below code, refer to the part after the comment Handle delete when 'caretPos' is zero.

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
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) throws Exception {
        BorderPane root = new BorderPane();
        Pane panel = new Pane();
        VBox box = new VBox();
        TextField tf = new TextField();
        Button characterButton = new Button("a");
        Button deleteChar = new Button("delete");

        box.getChildren().addAll(tf, characterButton, deleteChar);
        panel.getChildren().add(box);
        root.getChildren().add(panel);

        Scene scene = new Scene(root, 400, 400);
//        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();

        // handle caret pos
        AtomicInteger caretPos = new AtomicInteger();
        tf.caretPositionProperty().addListener((obs, oldVal, newVal) -> {
            System.out.println("newval: " + newVal);
            if (tf.isFocused()) {
                caretPos.set(newVal.intValue());
                System.out.println("Innernewval: " + newVal);
            }
        });
        // add character
        characterButton.setOnAction((event) -> {
            Button btn = (Button) event.getSource();
            System.out.println("Pressed " + btn.getText() + " button");
            int pos = caretPos.get();
            tf.insertText(pos, btn.getText());
            tf.requestFocus();
            tf.positionCaret(pos + 1);
            System.out.println("caretPos on add: " + caretPos.get());

        });
        // remove character
        deleteChar.setOnAction((event) -> {
            Button btn = (Button) event.getSource();
            System.out.println("Pressed " + btn.getText() + " button");

            // Handle delete when 'caretPos' is zero.
            if (caretPos.get() == 0) {
                if (tf.getText().isEmpty()) {
                    return; // Nothing to delete.
                }
                else {
                    caretPos.set(1); // Ensure 'newCaretPos' will not be negative.
                }
            }

            int newCaretPos = caretPos.get() - 1;
            tf.deleteText(newCaretPos, caretPos.get());
            tf.requestFocus();
            tf.positionCaret(newCaretPos);
            caretPos.set(newCaretPos);
            System.out.println("caretPos on delete: " + caretPos.get());
        });
    }
}

Edit

You are correct. When I run your code with JavaFX 8, I do reproduce the problem. After some debugging, the problem is that when the TextField contains a single character and you press deleteChar, the caretPositionProperty listener does not run and hence caretPosition is not updated and remains with the value 1 (one) instead of 0 (zero).

There are probably many workarounds to this problem. I chose to add the below if statement after the line System.out.println("caretPos on delete: " + caretPos.get()); in the event handler for deleteChar:

if (tf.getText().isEmpty()) {
    caretPos.set(0);
}

For the sake of completeness, here is the code I used to debug the program.

import java.util.concurrent.atomic.AtomicInteger;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            
            BorderPane root = new BorderPane();
            Pane panel = new Pane();
            VBox box = new VBox();
            TextField tf = new TextField();
            Button characterButton = new Button("a");
            Button deleteChar = new Button("delete");
            
            box.getChildren().addAll(tf, characterButton, deleteChar );
            panel.getChildren().add(box);
            root.getChildren().add(panel);
            
            Scene scene = new Scene(root,400,400);
//            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
            
            //handle caret pos
            AtomicInteger caretPos = new AtomicInteger();
            tf.caretPositionProperty().addListener((obs, oldVal, newVal) -> {
                System.out.println("newval" + newVal);
                if (tf.isFocused()) {
                    caretPos.set(newVal.intValue());
                    System.out.println("Innernewval" + newVal);
                }
            });
            //add character
            characterButton.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int pos = caretPos.get();
                System.out.println("###  DBUG  ### -> Adding: [Before 'insertText'] pos = " + pos);
                tf.insertText(pos, btn.getText());
                System.out.println("###  DBUG  ### -> Adding: [Before 'requestFocus'] pos = " + pos);
                tf.requestFocus();
                System.out.println("###  DBUG  ### -> Adding: [Before 'positionCaret'] pos = " + pos);
                tf.positionCaret(pos+1);
                System.out.println("caretPos on add: " + caretPos.get());
            });
            //remove character
            deleteChar.setOnAction(( event) -> {
                Button btn = (Button)event.getSource();
                System.out.println("Pressed " + btn.getText() + " button");
                int newCaretPos = caretPos.get()-1;
                System.out.println("###  DBUG  ### -> Deleting: [Before 'deleteText'] newCaretPos = " + newCaretPos);
                tf.deleteText(newCaretPos, caretPos.get());
                System.out.println("###  DBUG  ### -> Deleting: [Before 'requestFocus'] newCaretPos = " + newCaretPos);
                tf.requestFocus();
                System.out.println("###  DBUG  ### -> Deleting: [Before 'positionCaret'] newCaretPos = " + newCaretPos);
                tf.positionCaret(newCaretPos);   
                System.out.println("caretPos on delete: " + caretPos.get());
                if (tf.getText().isEmpty()) {
                    caretPos.set(0);
                }
            });
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

Here is the output when TextField contains a single character and I press deleteChar.

newval0
Pressed delete button
###  DBUG  ### -> Deleting: [Before 'deleteText'] newCaretPos = 0
###  DBUG  ### -> Deleting: [Before 'requestFocus'] newCaretPos = 0
###  DBUG  ### -> Deleting: [Before 'positionCaret'] newCaretPos = 0
caretPos on delete: 1

As you can see, the caretPositionProperty listener is not executed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文