Java 是否有一个“问题”;“最佳”;从静态方法调用类方法的方法?
我有多个控制器,每个控制器与不同的FXML文件关联。一个节点中有一个事件需要跨其他节点进行同步,因此我决定使用另一个事件以及各种控制器文件中的事件处理程序来执行此操作 要注册事件处理程序,需要事件处理程序方法是静态的(即,Java 是否有一个“问题”;“最佳”;从静态方法调用类方法的方法?,java,javafx,javafx-8,Java,Javafx,Javafx 8,我有多个控制器,每个控制器与不同的FXML文件关联。一个节点中有一个事件需要跨其他节点进行同步,因此我决定使用另一个事件以及各种控制器文件中的事件处理程序来执行此操作 要注册事件处理程序,需要事件处理程序方法是静态的(即,addEventHandler(SomeEvent,ClassName::MethodName)) 控制器看起来像 public class MyController { private static MyController selfRef = null;
addEventHandler(SomeEvent,ClassName::MethodName)
)
控制器看起来像
public class MyController {
private static MyController selfRef = null;
public MyController() {
selfRef = this;
}
public static void someEventHandler(Event event) {
if (selfRef != null) {
selfRef.doSomethingUseful();
}
}
private void doSomethingUseful() { /* synch the nodes */ }
}
这是可行的,但似乎有点困难。有没有更好的机制来实现相同的最终结果?也许您可以使用某种注册表来处理同步。下面是一个快速而肮脏的示例:
public class Synchronizer {
private ObservableList<Node> nodes;
private boolean isSyncing;
public Synchronizer() {
nodes = FXCollections.observableArrayList();
}
public void addNode(Node node) {
nodes.add(node);
}
public void sync(Node sourceNode, Event event) {
if (isSyncing) {
return;
}
isSyncing = true;
for (Node node : nodes) {
if (node != sourceNode) {
node.fireEvent(event);
}
}
isSyncing = false;
}
}
编辑:
这将有助于创建更干净的版本:
public class Starter extends Application {
@Override
public void start(Stage primaryStage) {
ViewController controller1 = new ViewController();
ViewController controller2 = new ViewController();
Synchronizer synchronizer = new Synchronizer();
synchronizer.add(controller1);
synchronizer.add(controller2);
VBox box = new VBox(controller1.root, controller2.root);
primaryStage.setScene(new Scene(box));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public interface SyncTarget {
Node getSyncNode();
void triggerAction();
}
public class Synchronizer {
private ObservableList<SyncTarget> syncTargets;
private EventHandler<Event> eventHandler;
public Synchronizer() {
syncTargets = FXCollections.observableArrayList();
eventHandler = e -> sync();
}
public void add(SyncTarget target) {
syncTargets.add(target);
target.getSyncNode().addEventHandler(ActionEvent.ANY, eventHandler);
}
public void remove(SyncTarget target) {
syncTargets.remove(target);
target.getSyncNode().removeEventHandler(ActionEvent.ANY, eventHandler);
}
public void sync() {
for (SyncTarget target : syncTargets) {
target.triggerAction();
}
}
}
public class ViewController implements SyncTarget {
private StackPane root;
private Button button;
public ViewController() {
button = new Button();
root = new StackPane(button);
}
@Override
public Node getSyncNode() {
return button;
}
@Override
public void triggerAction() {
//action
}
}
}
公共类启动程序扩展应用程序{
@凌驾
公共无效开始(阶段primaryStage){
ViewController控制器1=新的ViewController();
ViewController控制器2=新的ViewController();
同步器同步器=新同步器();
同步器。添加(控制器1);
同步器。添加(控制器2);
VBox box=新的VBox(controller1.root,controller2.root);
初级舞台.场景(新场景(框));
primaryStage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
公共接口同步目标{
节点getSyncNode();
无效触发作用();
}
公共类同步器{
私有可观测同步目标;
私有事件处理程序事件处理程序;
公共同步器(){
syncTargets=FXCollections.observableArrayList();
eventHandler=e->sync();
}
公共无效添加(同步目标){
syncTargets.add(目标);
target.getSyncNode().addEventHandler(ActionEvent.ANY,eventHandler);
}
公共无效删除(同步目标){
同步目标。删除(目标);
target.getSyncNode().removeEventHandler(ActionEvent.ANY,eventHandler);
}
公共void sync(){
对于(SyncTarget目标:syncTargets){
target.triggerAction();
}
}
}
公共类ViewController实现SyncTarget{
私有根;
私人按钮;
公共视图控制器(){
按钮=新按钮();
root=新堆栈窗格(按钮);
}
@凌驾
公共节点getSyncNode(){
返回按钮;
}
@凌驾
公共无效触发操作(){
//行动
}
}
}
如果您摆脱了所有静态内容,并使事件处理程序成为控制器类的成员,那么您可能会有更大的灵活性,如下所示
没有静态成员的示例实现
导入javafx.event.*;
导入javafx.fxml.*;
导入javafx.scene.scene;
导入javafx.scene.control.Label;
导入javafx.stage.*;
导入java.io.IOException;
类CustomerDialogController{
@FXML
自有品牌客户名称;
私有EventHandler customEventHandler=事件->{
//处理事件。。。
};
无效初始数据(客户){
customerName.setText(customer.getName());
}
公共事件处理程序getCustomEventHandler(){
返回customEventHandler;
}
}
公共类事件处理{
公共舞台showCustomerDialog(客户)引发IOException{
FXMLLoader=新的FXMLLoader(getClass().getResource(“customerDialog.fxml”);
舞台=新舞台(舞台风格装饰);
stage.setScene(新场景(loader.load());
CustomerDialogController=loader.getController();
controller.initData(客户);
stage.addEventHandler(Event.ANY,controller.getCustomEventHandler());
stage.show();
返回阶段;
}
}
类客户{
私有字符串名称;
客户(字符串名称){
this.name=名称;
}
公共字符串getName(){
返回名称;
}
}
实施方案说明
在本例中,事件处理程序已添加到后台,但它也可以添加到任何场景或节点或任何能够处理事件的对象
如果需要,还可以为事件处理程序添加一个setter,以允许外部更改事件处理逻辑
除了上面的设置之外,您可能希望控制器在其初始化方法中自注册事件处理程序。是否这样做取决于您是否希望在控制器外部公开注册事件处理程序,或者是否希望使用封装来隐藏控制器本地的所有事件处理逻辑控制器
关于(可能更优)备选方案的说明
作为一种替代方法,您可以使用第三方系统,例如
您还应该考虑为什么需要向应用程序添加自定义事件处理。JavaFX支持非常灵活的绑定和观察者模式。通过将模型对象的属性暴露为可观察的,通常不必有自定义事件。通常,视图控制器可以观察到相关模型对象的任何更改。根据UI交互修改模型对象的内部状态。如果您引入依赖项注入系统将模型注入控制器,例如Guice、Spring或。
它看起来像python-y,但是如果它可以工作,那么我猜您只需要使用Singleton。您考虑过Google Guava Ev吗entBus?它看起来很适合您的需要。“一个节点中有一个事件,需要跨其他节点进行同步”。使用MVC模式。每个控制器都应该有一个对共享模型实例的引用。控制器更新mopublic class Starter extends Application {
@Override
public void start(Stage primaryStage) {
ViewController controller1 = new ViewController();
ViewController controller2 = new ViewController();
Synchronizer synchronizer = new Synchronizer();
synchronizer.add(controller1);
synchronizer.add(controller2);
VBox box = new VBox(controller1.root, controller2.root);
primaryStage.setScene(new Scene(box));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public interface SyncTarget {
Node getSyncNode();
void triggerAction();
}
public class Synchronizer {
private ObservableList<SyncTarget> syncTargets;
private EventHandler<Event> eventHandler;
public Synchronizer() {
syncTargets = FXCollections.observableArrayList();
eventHandler = e -> sync();
}
public void add(SyncTarget target) {
syncTargets.add(target);
target.getSyncNode().addEventHandler(ActionEvent.ANY, eventHandler);
}
public void remove(SyncTarget target) {
syncTargets.remove(target);
target.getSyncNode().removeEventHandler(ActionEvent.ANY, eventHandler);
}
public void sync() {
for (SyncTarget target : syncTargets) {
target.triggerAction();
}
}
}
public class ViewController implements SyncTarget {
private StackPane root;
private Button button;
public ViewController() {
button = new Button();
root = new StackPane(button);
}
@Override
public Node getSyncNode() {
return button;
}
@Override
public void triggerAction() {
//action
}
}
}
import javafx.event.*;
import javafx.fxml.*;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.*;
import java.io.IOException;
class CustomerDialogController {
@FXML
private Label customerName;
private EventHandler<Event> customEventHandler = event -> {
// handle the event...
};
void initData(Customer customer) {
customerName.setText(customer.getName());
}
public EventHandler<Event> getCustomEventHandler() {
return customEventHandler;
}
}
public class EventHandling {
public Stage showCustomerDialog(Customer customer) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("customerDialog.fxml"));
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(new Scene(loader.load()));
CustomerDialogController controller = loader.getController();
controller.initData(customer);
stage.addEventHandler(Event.ANY, controller.getCustomEventHandler());
stage.show();
return stage;
}
}
class Customer {
private String name;
Customer(String name) {
this.name = name;
}
public String getName() {
return name;
}
}