由于插入符号位置,文本字段中的 Javafx indexOutOfBoundsException
Javafx indexOutOfBoundsException within Textfield due to caret Postion
我正在构建一个小型应用程序,其中 TextField
文本可通过屏幕上的按钮进行更新或删除。我已经利用此 中的代码来移动插入符号并添加文本。我可以在 TextField
中添加和删除字符,但是当 n 数量的字符被添加到 TextField
然后 n当您尝试添加另一个字符时,数量被删除 IndexOutOfBoundsException
,因为插入符号位置(当删除所有字符时)在它应该为 0 时变为 1。我不知道为什么它应该为 0 时变为 1。我在这里做错了什么?
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);
}
}
您的代码无法编译。你有 catch
而没有 try
。在下面的代码中,我删除了 [orphan] catch
块。此外,您的风格 sheet,即文件 application.css,与您的问题无关,因此为了使您问题中的代码成为 minimal, reproducible example我建议你删除那部分。它在下面的代码中被注释掉了。
当 caretPos
为零并且我按下 deleteChar
按钮时,我只得到 IndexOutOfBoundsException
。因此,您只需添加处理该 edge case 的代码。在下面的代码中,参考注释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());
});
}
}
编辑
你是对的。当我使用 JavaFX 8 运行 你的代码时,我确实重现了这个问题。经过一些调试,问题是当 TextField
包含单个字符并且您按 deleteChar
时,caretPositionProperty
侦听器不会 运行 因此 caretPosition
是未更新并保留值 1(一)而不是 0(零)。
这个问题可能有很多解决方法。我选择在 deleteChar
:
的事件处理程序中的 System.out.println("caretPos on delete: " + caretPos.get());
行之后添加以下 if
语句
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
侦听器未执行。
我正在构建一个小型应用程序,其中 TextField
文本可通过屏幕上的按钮进行更新或删除。我已经利用此 TextField
中添加和删除字符,但是当 n 数量的字符被添加到 TextField
然后 n当您尝试添加另一个字符时,数量被删除 IndexOutOfBoundsException
,因为插入符号位置(当删除所有字符时)在它应该为 0 时变为 1。我不知道为什么它应该为 0 时变为 1。我在这里做错了什么?
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);
}
}
您的代码无法编译。你有 catch
而没有 try
。在下面的代码中,我删除了 [orphan] catch
块。此外,您的风格 sheet,即文件 application.css,与您的问题无关,因此为了使您问题中的代码成为 minimal, reproducible example我建议你删除那部分。它在下面的代码中被注释掉了。
当 caretPos
为零并且我按下 deleteChar
按钮时,我只得到 IndexOutOfBoundsException
。因此,您只需添加处理该 edge case 的代码。在下面的代码中,参考注释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());
});
}
}
编辑
你是对的。当我使用 JavaFX 8 运行 你的代码时,我确实重现了这个问题。经过一些调试,问题是当 TextField
包含单个字符并且您按 deleteChar
时,caretPositionProperty
侦听器不会 运行 因此 caretPosition
是未更新并保留值 1(一)而不是 0(零)。
这个问题可能有很多解决方法。我选择在 deleteChar
:
System.out.println("caretPos on delete: " + caretPos.get());
行之后添加以下 if
语句
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
侦听器未执行。