JavaFX中如何通知所有监听指定事件的组件?
全局通知ChatEvent监听器组件的解决方案
现有代码
事件定义
/** * 消息事件 */ public class ChatEvent extends Event { public static final EventType<ChatEvent> CHAT_ANY = new EventType<>(Event.ANY, "CHAT"); public static final EventType<ChatEvent> RECEIVE_CHAT = new EventType<>(CHAT_ANY, "CHAT_RECEIVE"); private final Chat.ChatMessage chatMessage ; public ChatEvent(EventType<? extends Event> eventType, Chat.ChatMessage chatMessage ) { super(eventType); this.chatMessage = chatMessage ; } @Override public Object getSource() { return chatMessage; } public Chat.ChatMessage getChatMessage(){ return chatMessage; } public ChatEvent(Object source, EventTarget target, EventType<? extends Event> eventType,Chat.ChatMessage chatMessage) { super(source, target, eventType); this.chatMessage = chatMessage; } }
组件事件处理器
receiveMessage.addEventHandler(ChatEvent.RECEIVE_CHAT , (chat)-> { log.info("client receive message"); Chat.ChatMessage chatMessage = chat.getChatMessage(); MessagePane msgPane = new MessagePane(chatMessage); vBox.getChildren().add(msgPane); receiveMessage.setText(chatMessage.getContent()); });
当前事件触发方式
Runnable fireEvent = () -> EventUtil.fireEvent( receiveMessage,chatEvent ); if (!Platform.isFxApplicationThread()){ Platform.runLater(fireEvent); } else { fireEvent.run(); }
核心问题
当前EventUtil.fireEvent仅能触发指定组件的监听器,无法通知所有注册了ChatEvent.RECEIVE_CHAT的组件。
解决方案
要实现全局通知所有注册监听器的组件,推荐使用**事件总线(Event Bus)**模式,具体实现如下:
1. 实现全局事件总线
创建单例事件总线类,统一管理ChatEvent监听器并负责事件分发:
import javafx.application.Platform; import javafx.event.EventHandler; import java.util.concurrent.CopyOnWriteArrayList; import java.util.List; public class ChatEventBus { // 用CopyOnWriteArrayList避免并发修改异常 private final List<EventHandler<ChatEvent>> listeners = new CopyOnWriteArrayList<>(); // 单例实例 private static final ChatEventBus INSTANCE = new ChatEventBus(); private ChatEventBus() {} public static ChatEventBus getInstance() { return INSTANCE; } // 注册监听器 public void registerListener(EventHandler<ChatEvent> listener) { if (listener != null && !listeners.contains(listener)) { listeners.add(listener); } } // 移除监听器,避免内存泄漏 public void unregisterListener(EventHandler<ChatEvent> listener) { listeners.remove(listener); } // 触发事件,确保在FX应用线程执行 public void fireEvent(ChatEvent event) { if (Platform.isFxApplicationThread()) { dispatchEvent(event); } else { Platform.runLater(() -> dispatchEvent(event)); } } private void dispatchEvent(ChatEvent event) { for (EventHandler<ChatEvent> listener : listeners) { listener.handle(event); } } }
2. 修改组件监听器注册方式
不再向单个组件注册,改为向事件总线注册:
// 替换原有的receiveMessage.addEventHandler方式 ChatEventBus.getInstance().registerListener((chat)-> { log.info("client receive message"); Chat.ChatMessage chatMessage = chat.getChatMessage(); MessagePane msgPane = new MessagePane(chatMessage); vBox.getChildren().add(msgPane); receiveMessage.setText(chatMessage.getContent()); });
3. 修改事件触发逻辑
直接调用事件总线的fireEvent方法,无需指定目标组件:
ChatEventBus.getInstance().fireEvent(chatEvent);
注意事项
- 组件销毁时务必调用
ChatEventBus.getInstance().unregisterListener(listener),避免内存泄漏 - 若后续扩展多种
ChatEvent类型,可在事件总线中按EventType分类维护监听器列表
内容的提问来源于stack exchange,提问作者Peng
相关产品推荐
相关产品推荐

