- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的 InvalidationListener 有问题。它被设置为 SimpleStringProperty 上的监听器。但它只在第一次更改 SimpleStringProperty 时调用。我进入了 Debug模式并在调用 SimpleStringProperty::set 的行上创建了一个断点,它开始工作,直到我再次删除断点。
我制作了一个简短的可执行示例程序,它模拟了带有计时器的 SimpleStringProperty 的修改。您可以在没有断点的情况下运行程序一次,在这一行有一个断点:property.set(value);
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private SimpleStringProperty property;
private int counter;
@Override
public void start(Stage stage) {
// open a window to avoid immediately termination
stage.setWidth(800);
stage.setHeight(600);
BorderPane pane = new BorderPane();
stage.setScene(new Scene(pane));
stage.show();
// create a SimpleObjectProperty
property = new SimpleStringProperty();
property.addListener(observable ->
System.out.println("New value is: " + counter)
);
counter = 0;
// create timer to change 'property' every second
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(Duration.seconds(2), event ->{
String value = "" + ++counter;
System.out.println("Set property to: " + value);
property.set(value);
});
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.playFromStart();
}
public static void main(String[] args) {
launch(args);
}
}
我机器上的输出(Linux Mint 16.04 64 位,Oracle-Java 1.8.0_111):
Set property to: 1
New value is: 1
Set property to: 2
Set property to: 3
Set property to: 4
...
请给我解释一下:
最佳答案
一个可观察值有两种不同的状态,它们的变化可以触发监听器。有它的值,还有它当前是否有效的状态。
通常,可观察值的值可能是经过计算的值,而不是简单地存储在字段中。一旦该值被“实现”(我的术语),如果它被计算,则通过计算,或者如果它只是存储在一个字段中,则通过被检索,那么可观察值就处于“有效”状态。如果值发生变化(或可能已经发生变化),则可观察值变为“无效”,表明可能需要重新计算或再次查找。
仅当可观察值从有效状态转换为无效状态时,才会触发失效监听器。所以在你的代码中,你第一次调用
property.set(value);
属性转换为无效状态(因为最近检索到的值(如果有的话)不是其当前值)。
由于您从未调用过 property.get()
(或 property.getValue()
),因此该属性永远不会得到验证。因此,下次您调用 property.set(value)
时,该属性不会转换到无效状态(它已经处于该状态),因此监听器没有被解雇。
如果您将监听器代码替换为
property.addListener(observable ->
System.out.println("New value is: " + property.get())
);
此监听器将使该属性再次生效,因此每次都会触发监听器。
真正的问题是您在这里使用了错误类型的监听器。如果您想每次值更改时执行操作,请使用ChangeListener
,而不是InvalidationListener
:
property.addListener((observable, oldValue, newValue) ->
System.out.println("New value is: " + newValue)
);
在带有断点的 Debug模式下运行会导致每次调用失效监听器的观察结果很有趣。我有点猜测,但我怀疑正在发生的事情是,当您到达断点时,调试器会显示变量的当前值。这不可避免地涉及对属性调用 getValue()
(可能作为其 toString()
实现的一部分),因此属性得到验证。
您不太可能经常显式使用 InvalidationListener
。它们的主要用途是绑定(bind)。考虑以下示例:
DoubleProperty x = new SimpleDoubleProperty(3);
DoubleProperty y = new SimpleDoubleProperty(4);
DoubleBinding hyp = new DoubleBinding() {
{
bind(x);
bind(y);
}
@Override
protected double computeValue() {
System.out.println("Computing distance");
return Math.sqrt(x.get()*x.get() + y.get()*y.get());
}
};
Label hypLabel = new Label();
hypLabel.textProperty().bind(hyp.asString("Hypotenuse: %f"));
在绑定(bind)实现中调用bind(x)
意味着:当x
失效时,认为本次绑定(bind)失效。 y
也类似。当然,bind
的实现在底层使用了 InvalidationListener
。
这里的要点是 hyp
的值的计算非常昂贵。如果您要对 x
或 y
进行多项更改,则 hyp
将变得无效,并且需要在您再次需要时重新计算 。由于标签的文本属性绑定(bind)到 hyp
,这也意味着标签的文本无效。但是,只有在渲染脉冲中重新绘制标签时,您才真正需要新值;为 x
和 y
的每次更改计算值就太过分了。
关于java - InvalidationListener 仅在带有断点的 Debug模式下执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40477770/
我只关心属性是否已更改,而不是新值。 注册 InvalidationListener 而不是 ChangeListener 是否有利? 我假设对属性的更改首先会使该属性无效并通知所有无效监听器。仅当注
我有一个用例,我想将多个 ObservableValue 绑定(bind)到一个 Observable 上,因为我实际上不感兴趣,值的变化是什么,我只需要一种在更改时得到通知的方法。 所以这是 Obs
我的 InvalidationListener 有问题。它被设置为 SimpleStringProperty 上的监听器。但它只在第一次更改 SimpleStringProperty 时调用。我进入了
我有一个用例,我想将多个 ObservableValue 绑定(bind)到一个 Observable 上,因为我实际上对值变化是什么不感兴趣,我只需要一种在变化时收到通知的方法。 这就是 Obser
运行程序出现如下错误。 NoClassDefFoundError: javafx/beans/InvalidationListener 命令行如下 java -cp "%JAVA_HOME%\lib\
假设我有一个 JavaFX 应用程序,它有一个可观察类 SomeObservableClass 和一些属性: public class SomeObservableClass{ private S
我是一名优秀的程序员,十分优秀!