button.onActionProperty().addListener 在 javafx 中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22744334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
button.onActionProperty().addListener is not working in javafx
提问by johny reeder
I am new in Java and I am trying Java events but I am absolutely lost. I know events from C# where is no problem with it and they works perfectly, but Java is different universe . I tried to find something on internet but I can't figured it out long time so I am here.
我是 Java 新手,我正在尝试 Java 事件,但我完全迷失了。我知道来自 C# 的事件在那里没有问题并且它们完美地工作,但是 Java 是不同的宇宙。我试图在互联网上找到一些东西,但我很长时间都想不通,所以我在这里。
I have one object and I need trigger some action. When this action is triggered I need to call not only one event handler, but more of them from different objects.
我有一个对象,我需要触发一些操作。触发此操作时,我不仅需要调用一个事件处理程序,还需要调用来自不同对象的更多事件处理程序。
For example I just use Button
class.
例如,我只使用Button
类。
There are two ways how to do that:
有两种方法可以做到这一点:
One way is to use button.setOnAction
method. But this is not working because when I call this method second time (from another object) I just replace one event handler by another. You can see what I mean in code in method initEventsUselessWay()
.
一种方法是使用button.setOnAction
方法。但这不起作用,因为当我第二次(从另一个对象)调用此方法时,我只是将一个事件处理程序替换为另一个。你可以在 method 中的代码中看到我的意思initEventsUselessWay()
。
Second way is to use button.onActionProperty().addListener
. But this is not working at all. You can see in method initEventsNeededWay()
.
第二种方法是使用button.onActionProperty().addListener
. 但这根本行不通。你可以在方法中看到initEventsNeededWay()
。
So, why button.onActionProperty().addListener
is not working?
那么,为什么button.onActionProperty().addListener
不工作?
And is there any way how to do this in Javafx?
有什么方法可以在 Javafx 中做到这一点吗?
Finally I will not use Button class, but something like MyClass and I need to implement this here. But if this is not working on Button class it will not work on MyClas neither.
最后,我不会使用 Button 类,而是使用 MyClass 之类的东西,我需要在这里实现它。但是,如果这不适用于 Button 类,则它也不适用于 MyClas。
Thank you very much for advice.
非常感谢您的建议。
package sample;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class JavaEventsTest1589 extends Application {
private Button btnDemo1;
private Button btnDemo2;
@Override
public void start(Stage primaryStage) {
// panel
Pane rootPane = new Pane();
// scene
Scene scene = new Scene(rootPane, 300, 250);
primaryStage.setTitle("events demo");
primaryStage.setScene(scene);
// button 1
btnDemo1 = new Button();
rootPane.getChildren().add(btnDemo1);
btnDemo1.setText("Execute Demo 1");
btnDemo1.setLayoutX(50);
btnDemo1.setLayoutY(10);
// button 2
btnDemo2 = new Button();
rootPane.getChildren().add(btnDemo2);
btnDemo2.setText("Execute Demo 2");
btnDemo2.setLayoutX(50);
btnDemo2.setLayoutY(50);
initEventsUselessWay();
initEventsNeededWay();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private void initEventsUselessWay() {
btnDemo1.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
runDemoPrimaryReaction();
}
});
btnDemo1.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
runDemoSecondaryReaction();
}
});
}
private void initEventsNeededWay() {
btnDemo2.onActionProperty().addListener(new ChangeListener<EventHandler<ActionEvent>>() {
@Override
public void changed(ObservableValue<? extends EventHandler<ActionEvent>> observableValue, EventHandler<ActionEvent> actionEventEventHandler, EventHandler<ActionEvent> actionEventEventHandler2) {
runDemoThisINeed_No1();
}
});
btnDemo2.onActionProperty().addListener(new ChangeListener<EventHandler<ActionEvent>>() {
@Override
public void changed(ObservableValue<? extends EventHandler<ActionEvent>> observableValue, EventHandler<ActionEvent> actionEventEventHandler, EventHandler<ActionEvent> actionEventEventHandler2) {
runDemoThisINeed_No2();
}
});
}
private void runDemoPrimaryReaction() {
System.out.println("useless way - primary reaction");
}
private void runDemoSecondaryReaction() {
System.out.println("useless way - secondary reaction");
}
private void runDemoThisINeed_No1() {
System.out.println("not working way - No1");
}
private void runDemoThisINeed_No2() {
System.out.println("not working way - No2");
}
}
采纳答案by James_D
Use addEventHandler:
使用 addEventHandler:
btnDemo1.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
runDemoPrimaryReaction();
}
});
btnDemo1.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
runDemoSecondaryReaction();
}
});
I recommend using Java 8, in which case you can write
我推荐使用 Java 8,在这种情况下你可以编写
btnDemo1.addEventHandler(ActionEvent.ACTION, event -> runDemoPrimaryReaction());
btnDemo1.addEventHandler(ActionEvent.ACTION, event -> runDemoSecondaryReaction());
The setOnAction(...)
method is a "convenience" method. The way it works is that the Button
maintains an ObjectProperty<EventHandler<ActionEvent>>.
If you set the value of this property (to an EventHandler<ActionEvent>
), that event handler will automatically be added to the event handlers for the button. If you set it a second time, since it's just a property, it will replace the existing event handler. So you can use this for a slightly quicker approach in the case you only have one handler. (It also plays nicely with FXML.)
该setOnAction(...)
方法是一种“方便”的方法。它的工作方式是Button
维护一个ObjectProperty<EventHandler<ActionEvent>>.
如果您将此属性的值设置为EventHandler<ActionEvent>
,则该事件处理程序将自动添加到按钮的事件处理程序中。如果您再次设置它,因为它只是一个属性,它将替换现有的事件处理程序。因此,在您只有一个处理程序的情况下,您可以使用它来实现稍微快一点的方法。(它也可以很好地与 FXML 配合使用。)
onActionProperty().addListener(...)
is a different thing entirely: it listens for changes in the property itself. So if you register a listener in this way, then call setOnAction(...)
, the listener you registered with the property will be invoked when you call setOnAction
(not when the button is pressed).
onActionProperty().addListener(...)
完全是另一回事:它监听属性本身的变化。所以如果你用这种方式注册一个监听器,然后调用setOnAction(...)
,你用属性注册的监听器会在你调用的时候被调用setOnAction
(不是按下按钮的时候)。
Have a look at the tutorial, particularly the first section "Processing events" and the second "Working with convenience methods". The second section makes it clear when setOnAction is actually doing.
看看教程,特别是第一部分“处理事件”和第二部分“使用便捷方法”。第二部分明确说明了 setOnAction 何时实际执行。
回答by Benjamin Gale
You need to think of an 'action' as a property of the Button
rather than an event.
A Button
can only have one action at a time, hence you are setting it to one value and then changing it to another which means only the code in the second handler will execute.
您需要将“动作”视为 的属性Button
而不是事件。AButton
一次只能有一个动作,因此您将它设置为一个值,然后将其更改为另一个值,这意味着只有第二个处理程序中的代码将执行。
The action property is implemented using one of the JavaFX property classes which provides built in property change notification. When you call button.onActionProperty().addListener(...
you are adding a listener that will be invoked when the action is changed.
操作属性是使用提供内置属性更改通知的 JavaFX 属性类之一实现的。当您调用时,button.onActionProperty().addListener(...
您正在添加一个侦听器,该侦听器将在操作更改时被调用。
Try calling the addListener(...
code before calling setOnAction(...
and it should be clear what is happening.
addListener(...
在调用之前尝试调用代码setOnAction(...
,应该清楚发生了什么。
If you want to think of this in terms of C# then
如果您想从 C# 的角度考虑这一点,那么
button.setOnAction(..
is like a property e.g.button.Action = ...
button.onActionProperty().addListener(...
is like an event e.g.button.ActionChanged += ...
button.setOnAction(..
就像一个财产,例如button.Action = ...
button.onActionProperty().addListener(...
就像一个事件,例如button.ActionChanged += ...
If you are new to JavaFX and need some help with their particular implementation of properties and events I can suggest the following resources:
如果您是 JavaFX 的新手并且需要一些关于它们的属性和事件的特定实现的帮助,我可以建议以下资源:
- Creating JavaFX Properties
- Creating read-only properties in JavaFX
- JavaFX: Handling events
- JavaFX: Using properties and binding
Update:
更新:
After reading your comments I realise this isn't really JavaFX specific but about events in general. Events are just an implementation of the observer pattern (even in C#).
阅读您的评论后,我意识到这并不是真正针对 JavaFX 的,而是关于一般事件的。事件只是观察者模式的一个实现(即使在 C# 中)。
A basic implementation might look something like this although there is little point in writing this yourself as JavaFX does include a built in way registering listeners for events as demonstrated by James_D.
一个基本的实现可能看起来像这样,尽管自己编写这个没有什么意义,因为 JavaFX 确实包含一种内置的方式来注册事件的侦听器,如 James_D 所演示的。
public interface MyListener {
invoke();
}
class MyButton extends Button {
List<MyListener> listeners = new ArrayList<MyListener>();
public void addListener(MyListener toAdd) {
listeners.add(toAdd);
}
private void invoke() {
for (HelloListener l : listeners)
l.invoke();
}
this.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
this.invoke();
}
});
}
回答by AKS
Based on the OP's comment
基于 OP 的评论
So I exprect that when I click on button "Execute Demo 1" in console I will see in console two rows: 'useless way - primary reaction useless way - secondary reaction'
所以我预计当我点击控制台中的“执行演示 1”按钮时,我会在控制台中看到两行:“无用的方式 - 主要反应无用的方式 - 次要反应”
you need to call both the methods in the same event handler as following:
您需要在同一个事件处理程序中调用这两个方法,如下所示:
btnDemo1.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
runDemoPrimaryReaction();
runDemoSecondaryReaction();
}
});