![](/img/trans.png)
[英]Exception in thread “main” java.lang.IllegalMonitorStateException
[英]Thread communication: How to signal that a key was clicked? java.lang.IllegalMonitorStateException
我有一個帶有TextField的簡單JavaFX階段。 我想做的是:當用戶在TextField中插入字母時,我想打印“現在”(只是看它是否有效)。 我使用線程是因為稍后我想掃描字典,以查看用戶輸入的字母是否是詞典中單詞的一部分。
但是我得到了:java.lang.IllegalMonitorStateException
有任何想法嗎? 我似乎不太了解Condition.await和Multithreading的整個概念。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DictionaryThreading extends Application {
private static Lock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
public static void main(String[] args) {
launch();
}
private static class ScanWords implements Runnable{
@Override
public void run() {
lock.lock();
try{
while(true){
this.wait();
System.out.println("clicked");
}
} catch (Exception e){
e.printStackTrace();
} finally{
lock.unlock();
}
}
}
@Override
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
new ScanWords().run();
TextField tf = new TextField("Please enter a word");
tf.setOnKeyPressed(e -> {});
pane.getChildren().add(tf);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
無需創建一個除了等待用戶事件外不執行其他操作的線程。 JavaFX框架已經為您提供了此功能(它是任何 UI工具箱的基本功能之一)。 要響應文本字段中的文本更改,您需要做的就是在文本字段的text屬性中注冊一個更改偵聽器:
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
TextField tf = new TextField("Please enter a word");
tf.textProperty().addListener((obs, oldText, newText) -> {
System.out.println("text changed");
});
pane.getChildren().add(tf);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
如果需要花費很長時間來響應文本更改,那么您應該在文本字段的偵聽器中的后台線程中啟動該過程。 如果要搜索的內容很大,則可能要取消任何現有的搜索,以免最終並沒有同時運行大量搜索。 JavaFX Service
類提供了為此所需的功能:
public class SearchService extends Service<List<String>> {
// modify and access only on FX Application Thread:
private String searchString ;
@Override
protected Task<List<String>> createTask() {
final String s = searchString ;
return new Task<List<String>>() {
@Override
protected List<String> call() throws Exception {
List<String> matches = new ArrayList<>();
// do search for strings matching s
// be sure to check isCancelled() regularly
return matches ;
}
};
}
public String getSearchString() {
checkThread();
return searchString ;
}
public void setSearchString(String searchString) {
checkThread();
this.searchString = searchString ;
}
private void checkThread() {
if (! Platform.isFxApplicationThread()) {
throw new IllegalStateException("Not on FX Application Thread");
}
}
}
那你可以做
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
SearchService searchService = new SearchService();
searchService.setOnSucceeded(e -> {
List<String> matches = searchService.getValue();
// do whatever you need with search results...
// this is called on FX application thread
});
TextField tf = new TextField("Please enter a word");
tf.textProperty().addListener((obs, oldText, newText) -> {
searchService.cancel();
searchService.setSearchText(newText);
searchService.restart();
});
pane.getChildren().add(tf);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
我不使用JavaFX,但我認為您需要使用EventListener
。 嘗試使用TextListener
或InputMethodListener
。 例如:
StackPane pane = new StackPane();
TextField tf = new TextField("Please enter a word");
tf.addTextListener(e -> System.out.println("Pushed"));
pane.getChildren().add(tf);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
wait
方法應在synchronized
塊內執行:
try{
while(true){
synchronized(this){
this.wait();
System.out.println("clicked");
}
}
} catch (Exception e){
e.printStackTrace();
} finally{
lock.unlock();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.