• R/O
  • SSH
  • HTTPS

util: Commit


Commit MetaInfo

Revision209 (tree)
Zeit2019-12-20 10:58:27
Autorhirukawa_ryo

Log Message

* fx-util 0.3.3
コンテキストメニューからマウスカーソルが外れたときの振る舞い修正のバグを修正しました。(メニューアイテムを動的に追加した場合にリスナーが登録されず正しく動作しませんでした。)

Ändern Zusammenfassung

Diff

--- fx-util/trunk/src/main/java/net/osdn/util/javafx/scene/control/ContextMenuUtil.java (revision 208)
+++ fx-util/trunk/src/main/java/net/osdn/util/javafx/scene/control/ContextMenuUtil.java (revision 209)
@@ -1,8 +1,12 @@
11 package net.osdn.util.javafx.scene.control;
22
3+import javafx.beans.property.ReadOnlyObjectProperty;
4+import javafx.beans.value.ChangeListener;
5+import javafx.beans.value.ObservableValue;
6+import javafx.collections.ListChangeListener;
7+import javafx.collections.ObservableList;
38 import javafx.event.EventHandler;
49 import javafx.scene.Node;
5-import javafx.scene.Parent;
610 import javafx.scene.control.ContextMenu;
711 import javafx.scene.control.Menu;
812 import javafx.scene.control.MenuBar;
@@ -15,7 +19,12 @@
1519
1620 public class ContextMenuUtil {
1721
18- private static Map<ContextMenu, EventHandler<WindowEvent>> fixEventHandlers = new WeakHashMap<ContextMenu, EventHandler<WindowEvent>>();
22+ private static Map<ObservableList<Menu>, ListChangeListener<Menu>> menuListChangeListeners = new WeakHashMap<>();
23+ private static Map<ObservableList<MenuItem>, ListChangeListener<MenuItem>> menuItemListChangeListeners = new WeakHashMap<>();
24+ private static Map<ReadOnlyObjectProperty<ContextMenu>, ChangeListener<ContextMenu>> parentPopupChangeListeners = new WeakHashMap<>();
25+ private static Map<ContextMenu, EventHandler<WindowEvent>> contextMenuWindowShowingEventHandlers = new WeakHashMap<>();
26+ private static Map<Node, EventHandler<MouseEvent>> menuItemNodeMouseExitedEventHandlers = new WeakHashMap<>();
27+ private static Map<Node, EventHandler<MouseEvent>> menuItemNodeMouseReleasedEventFilters = new WeakHashMap<>();
1928
2029 /**
2130 * 指定したメニューバーに関連するコンテキスト・メニューの振る舞いを修正します。
@@ -27,7 +36,28 @@
2736 if(menuBar == null) {
2837 return null;
2938 }
30- for(Menu menu : menuBar.getMenus()) {
39+ ObservableList<Menu> menus = menuBar.getMenus();
40+ ListChangeListener<Menu> oldListChangeListener = menuListChangeListeners.get(menus);
41+ if(oldListChangeListener != null) {
42+ menus.removeListener(oldListChangeListener);
43+ menuListChangeListeners.remove(menus);
44+ }
45+ ListChangeListener<Menu> newListChangeListener = new ListChangeListener<Menu>() {
46+ @Override
47+ public void onChanged(Change<? extends Menu> c) {
48+ while(c.next()) {
49+ if(c.wasAdded()) {
50+ for(Menu menu : c.getAddedSubList()) {
51+ fix(menu);
52+ }
53+ }
54+ }
55+ }
56+ };
57+ menus.addListener(newListChangeListener);
58+ menuListChangeListeners.put(menus, newListChangeListener);
59+
60+ for(Menu menu : menus) {
3161 fix(menu);
3262 }
3363 return menuBar;
@@ -43,7 +73,28 @@
4373 if(menu == null) {
4474 return null;
4575 }
46- for(MenuItem menuItem : menu.getItems()) {
76+ ObservableList<MenuItem> menuItems = menu.getItems();
77+ ListChangeListener<MenuItem> oldListChangeListener = menuItemListChangeListeners.get(menuItems);
78+ if(oldListChangeListener != null) {
79+ menuItems.removeListener(oldListChangeListener);
80+ menuItemListChangeListeners.remove(menuItems);
81+ }
82+ ListChangeListener<MenuItem> newListChangeListener = new ListChangeListener<MenuItem>() {
83+ @Override
84+ public void onChanged(Change<? extends MenuItem> c) {
85+ while(c.next()) {
86+ if(c.wasAdded()) {
87+ for(MenuItem menuItem : c.getAddedSubList()) {
88+ fix(menuItem);
89+ }
90+ }
91+ }
92+ }
93+ };
94+ menuItems.addListener(newListChangeListener);
95+ menuItemListChangeListeners.put(menuItems, newListChangeListener);
96+
97+ for(MenuItem menuItem : menuItems) {
4798 fix(menuItem);
4899 }
49100 return menu;
@@ -59,17 +110,26 @@
59110 if(menuItem == null) {
60111 return null;
61112 }
62- menuItem.parentPopupProperty().addListener((observable, oldValue, newValue) -> {
63- if(oldValue != null) {
64- EventHandler<WindowEvent> oldEventHandler = fixEventHandlers.get(oldValue);
65- if(oldEventHandler != null) {
66- oldValue.removeEventHandler(WindowEvent.WINDOW_SHOWING, oldEventHandler);
113+ ReadOnlyObjectProperty<ContextMenu> parentPopup = menuItem.parentPopupProperty();
114+ ChangeListener<ContextMenu> oldChangeListener = parentPopupChangeListeners.get(parentPopup);
115+ if(oldChangeListener != null) {
116+ parentPopup.removeListener(oldChangeListener);
117+ parentPopupChangeListeners.remove(parentPopup);
118+ }
119+ ChangeListener<ContextMenu> newChangeListener = new ChangeListener<ContextMenu>() {
120+ @Override
121+ public void changed(ObservableValue<? extends ContextMenu> observable, ContextMenu oldValue, ContextMenu newValue) {
122+ if(oldValue != null) {
123+ removeListeners(oldValue);
67124 }
125+ if(newValue != null) {
126+ fix(newValue, false);
127+ }
68128 }
69- if(newValue != null) {
70- fix(newValue, false);
71- }
72- });
129+ };
130+ parentPopup.addListener(newChangeListener);
131+ parentPopupChangeListeners.put(parentPopup, newChangeListener);
132+
73133 return menuItem;
74134 }
75135
@@ -108,9 +168,10 @@
108168 if(contextMenu == null) {
109169 return null;
110170 }
111- EventHandler<WindowEvent> oldEventHandler = fixEventHandlers.get(contextMenu);
171+ EventHandler<WindowEvent> oldEventHandler = contextMenuWindowShowingEventHandlers.get(contextMenu);
112172 if(oldEventHandler != null) {
113173 contextMenu.removeEventHandler(WindowEvent.WINDOW_SHOWING, oldEventHandler);
174+ contextMenuWindowShowingEventHandlers.remove(contextMenu);
114175 }
115176 EventHandler<WindowEvent> newEventHandler = new EventHandler<WindowEvent>() {
116177 @Override
@@ -118,29 +179,88 @@
118179 Node contextMenuNode = contextMenu.getStyleableNode();
119180 for (MenuItem menuItem : contextMenu.getItems()) {
120181 Node menuItemNode = menuItem.getStyleableNode();
121- if(menuItemNode == null) {
122- continue;
123- }
124- menuItemNode.setOnMouseExited(me -> {
125- contextMenuNode.requestFocus();
126- });
127- menuItemNode.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> {
128- if(!menuItemNode.isFocused()) {
129- e.consume();
130- if(hideOnMouseReleased) {
131- contextMenu.hide();
132- }
133- }
134- });
182+ fixImpl(contextMenu, contextMenuNode, menuItem, menuItemNode, hideOnMouseReleased);
135183 }
136184 // コンテキスト・メニュー表示時になぜか先頭のアイテムが選択状態になることがあるようなので、
137185 // コンテキスト・メニュー自体にフォーカス要求を出して、先頭アイテムが初期選択状態にならないようにします。
138186 contextMenuNode.requestFocus();
139187 contextMenu.removeEventHandler(WindowEvent.WINDOW_SHOWING, this);
188+ contextMenuWindowShowingEventHandlers.remove(contextMenu);
140189 }
141190 };
142191 contextMenu.addEventHandler(WindowEvent.WINDOW_SHOWING, newEventHandler);
143- fixEventHandlers.put(contextMenu, newEventHandler);
192+ contextMenuWindowShowingEventHandlers.put(contextMenu, newEventHandler);
144193 return contextMenu;
145194 }
195+
196+ private static void fixImpl(ContextMenu contextMenu, Node contextMenuNode, MenuItem menuItem, Node menuItemNode, boolean hideOnMouseReleased) {
197+ if(contextMenu == null) {
198+ return;
199+ }
200+ if(contextMenuNode == null) {
201+ return;
202+ }
203+ if(menuItem == null) {
204+ return;
205+ }
206+ if(menuItemNode == null) {
207+ return;
208+ }
209+
210+ removeListeners(menuItemNode);
211+
212+ EventHandler<MouseEvent> newEventHandler = new EventHandler<MouseEvent>() {
213+ @Override
214+ public void handle(MouseEvent event) {
215+ contextMenuNode.requestFocus();
216+ }
217+ };
218+ menuItemNode.addEventHandler(MouseEvent.MOUSE_EXITED, newEventHandler);
219+ menuItemNodeMouseExitedEventHandlers.put(menuItemNode, newEventHandler);
220+
221+ EventHandler<MouseEvent> newEventFilter = new EventHandler<MouseEvent>() {
222+ @Override
223+ public void handle(MouseEvent event) {
224+ if(!menuItemNode.isFocused()) {
225+ event.consume();
226+ if(hideOnMouseReleased) {
227+ contextMenu.hide();
228+ }
229+ }
230+ }
231+ };
232+ menuItemNode.addEventFilter(MouseEvent.MOUSE_RELEASED, newEventFilter);
233+ menuItemNodeMouseReleasedEventFilters.put(menuItemNode, newEventFilter);
234+ }
235+
236+ private static void removeListeners(ContextMenu contextMenu) {
237+ if(contextMenu == null) {
238+ return;
239+ }
240+ for(MenuItem menuItem : contextMenu.getItems()) {
241+ Node menuItemNode = menuItem.getStyleableNode();
242+ removeListeners(menuItemNode);
243+ }
244+ EventHandler<WindowEvent> oldEventHandler = contextMenuWindowShowingEventHandlers.get(contextMenu);
245+ if(oldEventHandler != null) {
246+ contextMenu.removeEventHandler(WindowEvent.WINDOW_SHOWING, oldEventHandler);
247+ contextMenuWindowShowingEventHandlers.remove(contextMenu);
248+ }
249+ }
250+
251+ private static void removeListeners(Node menuItemNode) {
252+ if(menuItemNode == null) {
253+ return;
254+ }
255+ EventHandler<MouseEvent> oldEventHandler = menuItemNodeMouseExitedEventHandlers.get(menuItemNode);
256+ if(oldEventHandler != null) {
257+ menuItemNode.removeEventHandler(MouseEvent.MOUSE_EXITED, oldEventHandler);
258+ menuItemNodeMouseExitedEventHandlers.remove(menuItemNode);
259+ }
260+ EventHandler<MouseEvent> oldEventFilter = menuItemNodeMouseReleasedEventFilters.get(menuItemNode);
261+ if(oldEventFilter != null) {
262+ menuItemNode.removeEventFilter(MouseEvent.MOUSE_RELEASED, oldEventFilter);
263+ menuItemNodeMouseReleasedEventFilters.remove(menuItemNode);
264+ }
265+ }
146266 }
Show on old repository browser