如何在 JavaFX 的 TextArea 实现回车发送信息而不换行,但组合键 Ctrl + Enter 换行
如何在 JavaFX 的 TextArea 實現回車發送信息而不換行,但組合鍵 Ctrl + Enter 換行
??JavaFX 的惱人之處在于很多基本的操作都要自己親力親為。在默認情況下,在 TextArea 輸入回車會導致換行,但在很多場景中,我們希望它在用戶輸入回車不換行而改為觸發信息的發送,換行則由組合鍵 Ctrl + Enter 來觸發。在 JavaFX,這項功能沒有簡單直接的方法,并不是在所有的 UI 語言中都是如此,但 JavaFX 沒有提供直接的 API。在不斷踩坑之后,筆者終于在 JavaFX 中實現了這一功能。
實現的算法大致如下:
使用 TextArea 的處理器 onKeyPressed 來監聽 TextArea 的鍵盤輸入事件。
如果監聽到用戶輸入了回車,作如下判斷:
如果用戶輸入的不是組合鍵 Ctrl + Enter,去掉剛剛輸入的換行符,然后將文本發送。此時可以選擇清空文本框的內容還是保持文本框的內容不變。然后本算法結束。
如果用戶輸入的是組合鍵 Ctrl + Enter,在光標處插入換行符,然后將光標移至到換行符之后。然后本算法結束。
如果用戶沒有輸入回車,什么也不做,本算法結束。
主要的注意事項如下:
-
文本框光標的范圍是 [0, length]。因為光標指向文字左右及之間的空隙,而空隙的數量比文字多 1。
-
處理器 onKeyPressed 的回調方法是在用戶按下按鍵(還沒釋放之前)就馬上觸發。
-
TextArea 不認為輸入的組合鍵為單獨依次這些鍵的效果之和。這意味著,在按下但不松開 Ctrl 鍵之后,輸入 Enter 時,輸入的文本不會包含換行符,因為 TextArea 不認為此時輸入的是 Enter。但如果依次按下(不松開) a、Enter,則輸入的文本為 a\n。
-
在 onKeyPressed 的回調方法中,當用戶輸入的是普通的按鍵時,光標的位置為輸入該字符之前的位置(剛剛輸入的字符尚未在文本框中生效)。如果用戶輸入的是特殊的按鍵(如 Ctrl、Alt 、Enter 等),光標的位置為此鍵生效之后光標的位置。這意味著,如果輸入的是 Enter,則當 onKeyPressed 的回調方法觸發時,文本框中不僅包含換行符,而光標在該換行符之后。
-
在拼接光標兩側的文本時,Enter 與組合鍵 Ctrl + Enter 的光標位置與文本內容均有差異。對于 Enter,需要清除換行符,而輸入的換行符位于光標的左邊。對于組合鍵 Ctrl + Enter,不僅要插入換行符,還要將光標的位置右移。
-
Windows 會將回車解釋成 \n\r,但 TextArea 清除文本中所有的 \r。換句話說,當在 Windows 輸入回車時,實際上輸入的是 \n\r。但當向 TextArea 輸入 \n\r 時,TextArea 會移除所有的 \r。從 TextArea 得到的字符串中不會包含任何 \r。
-
方法 keyEvent.isControlDown() 并不是用來判斷觸發 onKeyPressed 的按鍵(剛剛按下的按鍵)是不是鍵 Ctrl ,而是用來判斷,在調用方法 keyEvent.isControlDown() 時,已經按下且未松開的按鍵含不含鍵 Ctrl。因此,如果使用該方法,就無需自行記錄用戶按下與釋放的每一個鍵了。
核心代碼如下:(FXML 與 FXML 的控制器的代碼)
TextSend.fxml
<?xml version="1.0" encoding="UTF-8"?><?import javafx.scene.layout.VBox?> <?import javafx.scene.control.TextArea?> <?import javafx.scene.control.Button?> <?import javafx.geometry.Insets?><VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"fx:controller="org.wangpai.demo.textsend.TextSendController"><padding><Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/></padding><TextArea prefHeight="200" prefWidth="200" fx:id="textArea" onKeyPressed="#onKeyPressedTextArea"/><Button onAction="#onActionButton" text="發送(S)"/> </VBox>TextSendController.java
package org.wangpai.demo.textsend;import javafx.fxml.FXML; import javafx.event.ActionEvent; import javafx.scene.control.TextArea; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent;public class TextSendController {@FXMLprivate TextArea textArea;@FXMLpublic void onKeyPressedTextArea(KeyEvent keyEvent) {// 如果按下了回車鍵if (keyEvent.getCode() == KeyCode.ENTER) {// 獲得此時的光標位置。此位置為剛剛輸入的換行符之后var caretPosition = this.textArea.getCaretPosition();// 如果已經按下的按鍵中包含 Control 鍵if (!keyEvent.isControlDown()) { // 如果輸入的不是組合鍵 `Ctrl+Enter`,去掉換行符,然后將文本發送// 獲得輸入文本,此文本包含剛剛輸入的換行符var text = this.textArea.getText();// 獲得換行符兩邊的文本var front = text.substring(0, caretPosition - 1);var end = text.substring(caretPosition);this.textArea.setText(front + end);this.onActionButton(null); // 模擬發送/*----- 如果希望發送后保留輸入框文本,需要只使用下面這行代碼,然后去掉清除文本框的代碼 -------*/// this.textArea.positionCaret(caretPosition - 1);} else {// 獲得輸入文本,此文本不包含剛剛輸入的換行符var text = this.textArea.getText();// 獲得光標兩邊的文本var front = text.substring(0, caretPosition);var end = text.substring(caretPosition);// 在光標處插入換行符this.textArea.setText(front + System.lineSeparator() + end);// 將光標移至換行符this.textArea.positionCaret(caretPosition + 1);}}}/*** 模擬的發送方法*/@FXMLpublic void onActionButton(ActionEvent event) {System.out.println("正在發送信息...");System.out.println(this.textArea.getText());this.textArea.requestFocus();/*----- 如果希望發送后清除輸入框文本,使用下面這行代碼 -------*/this.textArea.clear();} }示例程序運行截圖如下:
筆者的運行環境:
-
JDK 17.0.1
-
JavaFX 17.0.1
-
IntelliJ IDEA 2021.2.2 (Ultimate Edition)
完整的代碼:https://gitcode.net/wangpaiblog/20211124-textsend
總結
以上是生活随笔為你收集整理的如何在 JavaFX 的 TextArea 实现回车发送信息而不换行,但组合键 Ctrl + Enter 换行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LocalDateTime 的常用操作
- 下一篇: 在 JavaFX 中,如何计算文本所占像