[英]Thread communication: How to signal that a key was clicked? java.lang.IllegalMonitorStateException
i have a simple JavaFX stage with a TextField. 我有一个带有TextField的简单JavaFX阶段。 What i want to do is: when user inserts letters into the TextField, i want to print "now" (just to look if it works). 我想做的是:当用户在TextField中插入字母时,我想打印“现在”(只是看它是否有效)。 Im using a Thread because later i want to scan a dictonary to see, if the letters the user entered are part of words from the dictionary. 我使用线程是因为稍后我想扫描字典,以查看用户输入的字母是否是词典中单词的一部分。
But i get: java.lang.IllegalMonitorStateException 但是我得到了:java.lang.IllegalMonitorStateException
Any ideas? 有任何想法吗? I don't seem to understand the whole concept of Condition.await and Multithreading.. 我似乎不太了解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();
}
}
There is no need to create a thread that does nothing other than wait for user events. 无需创建一个除了等待用户事件外不执行其他操作的线程。 The JavaFX framework already provides this for you (it is one of the fundamental pieces of functionality of any UI toolkit). JavaFX框架已经为您提供了此功能(它是任何 UI工具箱的基本功能之一)。 All you need to do to respond to changes in the text in a text field is register a change listener with the text field's text property: 要响应文本字段中的文本更改,您需要做的就是在文本字段的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();
}
If the thing you need to do in response to the text changing takes a long time, then you should launch that process in a background thread in the listener on the text field. 如果需要花费很长时间来响应文本更改,那么您应该在文本字段的侦听器中的后台线程中启动该过程。 If you are searching something large, you probably want to cancel any existing search, so that you don't end up with a large number of searches all running concurrently. 如果要搜索的内容很大,则可能要取消任何现有的搜索,以免最终并没有同时运行大量搜索。 The JavaFX Service
class provides the functionality you need for this: 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");
}
}
}
Then you can do 那你可以做
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();
}
I don't use JavaFX, but I think you need to use EventListener
. 我不使用JavaFX,但我认为您需要使用EventListener
。 Try to use TextListener
or InputMethodListener
. 尝试使用TextListener
或InputMethodListener
。 For example: 例如:
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
method should be executed within synchronized
block: 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.