我有一段很像这样的代码:
package blah;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextInputControl;
import javafx.stage.Stage;
public class SimpleExample {
TextInputControl textFieldForWork;
LocalTextChangeListener localTextChangeListener;
public SimpleExample(TextInputControl textFieldForWork, Stage s) {
this.textFieldForWork = textFieldForWork;
localTextChangeListener = new LocalTextChangeListener();
System.out.println("Creating new focus listener for TextField component");
LocalFocusListener localFocusListener = new LocalFocusListener();
s.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (observable.getValue().toString().equals("false")) {
System.out.println("Removing TextField focus listener");
textFieldForWork.focusedProperty().removeListener(localFocusListener);
} else {
System.out.println("Adding TextField focus listener");
textFieldForWork.focusedProperty().addListener(localFocusListener);
}
}
});
}
private class LocalFocusListener implements ChangeListener {
@Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (observable.getValue().toString().equals("true")) {
System.out.println("Adding text change listener");
textFieldForWork.textProperty().addListener(localTextChangeListener);
} else {
System.out.println("Removing text change listener");
textFieldForWork.textProperty().removeListener(localTextChangeListener);
}
}
}
private class LocalTextChangeListener implements ChangeListener {
@Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
System.out.println("Textfield changed - do processing");
}
}}
此代码的目的是每次用户在文本字段中键入内容时触发侦听器。此代码的另一个必要功能是,在对话框散焦时,应删除文本字段侦听器。
任何帮助表示赞赏!
答案 0 :(得分:1)
我不确定我真的明白为什么你需要观察舞台的焦点属性。你不能只用文本字段注册一个监听器并留在那里吗?除非文本发生变化,否则不会调用它。
如果您真的需要您描述的功能,您可以这样做。以下是对正在发生的事情的描述:
文本字段的focusedProperty
会跟踪当前场景图中具有焦点的Node
是否为文本字段。它是场景图中的本地图#34;这意味着它与窗口是活动窗口还是聚焦窗口无关。
窗口的focusedProperty
跟踪窗口是否具有焦点。如果将应用程序移动到后台等,则会发生这种情况。
显然,在您创建文本字段时,尚未将其添加到场景或窗口中,所以只需执行
textFieldForWork.getScene().getWindow().focusedProperty().addListener(...)
无法工作,因为getScene()
此时会返回null
。即使场景非空,它可能还不属于某个窗口,因此您可能会getScene()
非空,但getScene().getWindow()
为空。
所以你真正想做的是观察属性的顺序。从textFieldForWork.sceneProperty()
开始并观察它;如果它发生变化且非空,则观察textFieldForInput.getScene().windowProperty()
;如果更改并且为非null,请观察textFieldForInput.getScene().getWindow().focusedProperty()
。
您可以自己处理,为链中的每个步骤创建侦听器,并根据需要添加和删除它们,但EasyBind框架具有管理此用例的API。使用EasyBind你可以做到
MonadicObservableValue<Boolean> stageFocused =
EasyBind.monadic(textFieldForWork.sceneProperty())
.flatMap(Scene::windowProperty)
.flatMap(Window::focusedProperty)
.orElse(false);
stageFocused.addListener((obs, wasFocused, isNowFocused) -> {
if (isNowFocused) {
// stage now has focus...
} else {
// stage has lost focus...
}
});
如果要检查文本字段具有焦点和的条件,包含它的窗口具有焦点,则可以执行
BooleanBinding stageAndTextFieldFocused = Bindings.createBooleanBinding(() ->
stageFocused.get() && tf.isFocused(),
stageFocused, tf.focusedProperty());
如上所述stageFocused
。然后就做
stageAndTextFieldFocused.addListener((obs, wasFocused, isNowFocused) ->
{ /* etc ... */ });