Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

577
LINES

< > BotCompany Repo | #1020525 // JMenuScroller

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (5289L/29K).

1  
/**
2  
 * A class that provides scrolling capabilities to a long menu dropdown or
3  
 * popup menu.  A number of items can optionally be frozen at the top and/or
4  
 * bottom of the menu.
5  
 * <P>
6  
 * <B>Implementation note:</B>  The default number of items to display
7  
 * at a time is 15, and the default scrolling interval is 125 milliseconds.
8  
 * <P>
9  
 *
10  
 * @version 1.5.0 04/05/12
11  
 * @author Darryl
12  
 * https://tips4java.wordpress.com/2009/02/01/menu-scroller/
13  
 */
14  
 
15  
import javax.swing.Icon;
16  
17  
sclass JMenuScroller {
18  
19  
  VF1<JPopupMenu> fillMenu;
20  
  private JPopupMenu menu;
21  
  private Component[] menuItems;
22  
  private MenuScrollItem upItem;
23  
  private MenuScrollItem downItem;
24  
  private final MenuScrollListener menuListener = new MenuScrollListener();
25  
  private int scrollCount;
26  
  private int interval;
27  
  private int topFixedCount;
28  
  private int bottomFixedCount;
29  
  private int firstIndex = 0;
30  
  private int keepVisibleIndex = -1;
31  
32  
  /**
33  
   * Registers a menu to be scrolled with the default number of items to
34  
   * display at a time and the default scrolling interval.
35  
   * 
36  
   * @param menu the menu
37  
   * @return the JMenuScroller
38  
   */
39  
  public static JMenuScroller setScrollerFor(JMenu menu) {
40  
    return new JMenuScroller(menu);
41  
  }
42  
43  
  /**
44  
   * Registers a popup menu to be scrolled with the default number of items to
45  
   * display at a time and the default scrolling interval.
46  
   * 
47  
   * @param menu the popup menu
48  
   * @return the JMenuScroller
49  
   */
50  
  public static JMenuScroller setScrollerFor(JPopupMenu menu) {
51  
    return new JMenuScroller(menu);
52  
  }
53  
54  
  /**
55  
   * Registers a menu to be scrolled with the default number of items to
56  
   * display at a time and the specified scrolling interval.
57  
   * 
58  
   * @param menu the menu
59  
   * @param scrollCount the number of items to display at a time
60  
   * @return the JMenuScroller
61  
   * @throws IllegalArgumentException if scrollCount is 0 or negative
62  
   */
63  
  public static JMenuScroller setScrollerFor(JMenu menu, int scrollCount) {
64  
    return new JMenuScroller(menu, scrollCount);
65  
  }
66  
67  
  /**
68  
   * Registers a popup menu to be scrolled with the default number of items to
69  
   * display at a time and the specified scrolling interval.
70  
   * 
71  
   * @param menu the popup menu
72  
   * @param scrollCount the number of items to display at a time
73  
   * @return the JMenuScroller
74  
   * @throws IllegalArgumentException if scrollCount is 0 or negative
75  
   */
76  
  public static JMenuScroller setScrollerFor(JPopupMenu menu, int scrollCount) {
77  
    return new JMenuScroller(menu, scrollCount);
78  
  }
79  
80  
  /**
81  
   * Registers a menu to be scrolled, with the specified number of items to
82  
   * display at a time and the specified scrolling interval.
83  
   * 
84  
   * @param menu the menu
85  
   * @param scrollCount the number of items to be displayed at a time
86  
   * @param interval the scroll interval, in milliseconds
87  
   * @return the JMenuScroller
88  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
89  
   */
90  
  public static JMenuScroller setScrollerFor(JMenu menu, int scrollCount, int interval) {
91  
    return new JMenuScroller(menu, scrollCount, interval);
92  
  }
93  
94  
  /**
95  
   * Registers a popup menu to be scrolled, with the specified number of items to
96  
   * display at a time and the specified scrolling interval.
97  
   * 
98  
   * @param menu the popup menu
99  
   * @param scrollCount the number of items to be displayed at a time
100  
   * @param interval the scroll interval, in milliseconds
101  
   * @return the JMenuScroller
102  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
103  
   */
104  
  public static JMenuScroller setScrollerFor(JPopupMenu menu, int scrollCount, int interval) {
105  
    return new JMenuScroller(menu, scrollCount, interval);
106  
  }
107  
108  
  /**
109  
   * Registers a menu to be scrolled, with the specified number of items
110  
   * to display in the scrolling region, the specified scrolling interval,
111  
   * and the specified numbers of items fixed at the top and bottom of the
112  
   * menu.
113  
   * 
114  
   * @param menu the menu
115  
   * @param scrollCount the number of items to display in the scrolling portion
116  
   * @param interval the scroll interval, in milliseconds
117  
   * @param topFixedCount the number of items to fix at the top.  May be 0.
118  
   * @param bottomFixedCount the number of items to fix at the bottom. May be 0
119  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or
120  
   * negative or if topFixedCount or bottomFixedCount is negative
121  
   * @return the JMenuScroller
122  
   */
123  
  public static JMenuScroller setScrollerFor(JMenu menu, int scrollCount, int interval,
124  
          int topFixedCount, int bottomFixedCount) {
125  
    return new JMenuScroller(menu, scrollCount, interval,
126  
            topFixedCount, bottomFixedCount);
127  
  }
128  
129  
  /**
130  
   * Registers a popup menu to be scrolled, with the specified number of items
131  
   * to display in the scrolling region, the specified scrolling interval,
132  
   * and the specified numbers of items fixed at the top and bottom of the
133  
   * popup menu.
134  
   * 
135  
   * @param menu the popup menu
136  
   * @param scrollCount the number of items to display in the scrolling portion
137  
   * @param interval the scroll interval, in milliseconds
138  
   * @param topFixedCount the number of items to fix at the top.  May be 0
139  
   * @param bottomFixedCount the number of items to fix at the bottom.  May be 0
140  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or
141  
   * negative or if topFixedCount or bottomFixedCount is negative
142  
   * @return the JMenuScroller
143  
   */
144  
  public static JMenuScroller setScrollerFor(JPopupMenu menu, int scrollCount, int interval,
145  
          int topFixedCount, int bottomFixedCount) {
146  
    return new JMenuScroller(menu, scrollCount, interval,
147  
            topFixedCount, bottomFixedCount);
148  
  }
149  
150  
  /**
151  
   * Constructs a <code>JMenuScroller</code> that scrolls a menu with the
152  
   * default number of items to display at a time, and default scrolling
153  
   * interval.
154  
   * 
155  
   * @param menu the menu
156  
   */
157  
  public JMenuScroller(JMenu menu) {
158  
    this(menu, 15);
159  
  }
160  
161  
  /**
162  
   * Constructs a <code>JMenuScroller</code> that scrolls a popup menu with the
163  
   * default number of items to display at a time, and default scrolling
164  
   * interval.
165  
   * 
166  
   * @param menu the popup menu
167  
   */
168  
  public JMenuScroller(JPopupMenu menu) {
169  
    this(menu, 15);
170  
  }
171  
172  
  /**
173  
   * Constructs a <code>JMenuScroller</code> that scrolls a menu with the
174  
   * specified number of items to display at a time, and default scrolling
175  
   * interval.
176  
   * 
177  
   * @param menu the menu
178  
   * @param scrollCount the number of items to display at a time
179  
   * @throws IllegalArgumentException if scrollCount is 0 or negative
180  
   */
181  
  public JMenuScroller(JMenu menu, int scrollCount) {
182  
    this(menu, scrollCount, 150);
183  
  }
184  
185  
  /**
186  
   * Constructs a <code>JMenuScroller</code> that scrolls a popup menu with the
187  
   * specified number of items to display at a time, and default scrolling
188  
   * interval.
189  
   * 
190  
   * @param menu the popup menu
191  
   * @param scrollCount the number of items to display at a time
192  
   * @throws IllegalArgumentException if scrollCount is 0 or negative
193  
   */
194  
  public JMenuScroller(JPopupMenu menu, int scrollCount) {
195  
    this(menu, scrollCount, 150);
196  
  }
197  
198  
  /**
199  
   * Constructs a <code>JMenuScroller</code> that scrolls a menu with the
200  
   * specified number of items to display at a time, and specified scrolling
201  
   * interval.
202  
   * 
203  
   * @param menu the menu
204  
   * @param scrollCount the number of items to display at a time
205  
   * @param interval the scroll interval, in milliseconds
206  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
207  
   */
208  
  public JMenuScroller(JMenu menu, int scrollCount, int interval) {
209  
    this(menu, scrollCount, interval, 0, 0);
210  
  }
211  
212  
  /**
213  
   * Constructs a <code>JMenuScroller</code> that scrolls a popup menu with the
214  
   * specified number of items to display at a time, and specified scrolling
215  
   * interval.
216  
   * 
217  
   * @param menu the popup menu
218  
   * @param scrollCount the number of items to display at a time
219  
   * @param interval the scroll interval, in milliseconds
220  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
221  
   */
222  
  public JMenuScroller(JPopupMenu menu, int scrollCount, int interval) {
223  
    this(menu, scrollCount, interval, 0, 0);
224  
  }
225  
226  
  /**
227  
   * Constructs a <code>JMenuScroller</code> that scrolls a menu with the
228  
   * specified number of items to display in the scrolling region, the
229  
   * specified scrolling interval, and the specified numbers of items fixed at
230  
   * the top and bottom of the menu.
231  
   * 
232  
   * @param menu the menu
233  
   * @param scrollCount the number of items to display in the scrolling portion
234  
   * @param interval the scroll interval, in milliseconds
235  
   * @param topFixedCount the number of items to fix at the top.  May be 0
236  
   * @param bottomFixedCount the number of items to fix at the bottom.  May be 0
237  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or
238  
   * negative or if topFixedCount or bottomFixedCount is negative
239  
   */
240  
  public JMenuScroller(JMenu menu, int scrollCount, int interval,
241  
          int topFixedCount, int bottomFixedCount) {
242  
    this(menu.getPopupMenu(), scrollCount, interval, topFixedCount, bottomFixedCount);
243  
  }
244  
245  
  /**
246  
   * Constructs a <code>JMenuScroller</code> that scrolls a popup menu with the
247  
   * specified number of items to display in the scrolling region, the
248  
   * specified scrolling interval, and the specified numbers of items fixed at
249  
   * the top and bottom of the popup menu.
250  
   * 
251  
   * @param menu the popup menu
252  
   * @param scrollCount the number of items to display in the scrolling portion
253  
   * @param interval the scroll interval, in milliseconds
254  
   * @param topFixedCount the number of items to fix at the top.  May be 0
255  
   * @param bottomFixedCount the number of items to fix at the bottom.  May be 0
256  
   * @throws IllegalArgumentException if scrollCount or interval is 0 or
257  
   * negative or if topFixedCount or bottomFixedCount is negative
258  
   */
259  
  public JMenuScroller(JPopupMenu menu, int scrollCount, int interval,
260  
          int topFixedCount, int bottomFixedCount) {
261  
    if (scrollCount <= 0 || interval <= 0) {
262  
      throw new IllegalArgumentException("scrollCount and interval must be greater than 0");
263  
    }
264  
    if (topFixedCount < 0 || bottomFixedCount < 0) {
265  
      throw new IllegalArgumentException("topFixedCount and bottomFixedCount cannot be negative");
266  
    }
267  
268  
    upItem = new MenuScrollItem(UP, -1);
269  
    downItem = new MenuScrollItem(DOWN, +1);
270  
    setScrollCount(scrollCount);
271  
    setInterval(interval);
272  
    setTopFixedCount(topFixedCount);
273  
    setBottomFixedCount(bottomFixedCount);
274  
275  
    this.menu = menu;
276  
    menu.addPopupMenuListener(menuListener);
277  
  }
278  
279  
  /**
280  
   * Returns the scroll interval in milliseconds
281  
   * 
282  
   * @return the scroll interval in milliseconds
283  
   */
284  
  public int getInterval() {
285  
    return interval;
286  
  }
287  
288  
  /**
289  
   * Sets the scroll interval in milliseconds
290  
   * 
291  
   * @param interval the scroll interval in milliseconds
292  
   * @throws IllegalArgumentException if interval is 0 or negative
293  
   */
294  
  public void setInterval(int interval) {
295  
    if (interval <= 0) {
296  
      throw new IllegalArgumentException("interval must be greater than 0");
297  
    }
298  
    upItem.setInterval(interval);
299  
    downItem.setInterval(interval);
300  
    this.interval = interval;
301  
  }
302  
303  
  /**
304  
   * Returns the number of items in the scrolling portion of the menu.
305  
   *
306  
   * @return the number of items to display at a time
307  
   */
308  
  public int getscrollCount() {
309  
    return scrollCount;
310  
  }
311  
312  
  /**
313  
   * Sets the number of items in the scrolling portion of the menu.
314  
   * 
315  
   * @param scrollCount the number of items to display at a time
316  
   * @throws IllegalArgumentException if scrollCount is 0 or negative
317  
   */
318  
  public void setScrollCount(int scrollCount) {
319  
    if (scrollCount <= 0) {
320  
      throw new IllegalArgumentException("scrollCount must be greater than 0");
321  
    }
322  
    this.scrollCount = scrollCount;
323  
    // XXX the following line closes all menus then this menu is made.
324  
    // That doesn't seem right.
325  
    // MenuSelectionManager.defaultManager().clearSelectedPath();
326  
  }
327  
328  
  /**
329  
   * Returns the number of items fixed at the top of the menu or popup menu.
330  
   * 
331  
   * @return the number of items
332  
   */
333  
  public int getTopFixedCount() {
334  
    return topFixedCount;
335  
  }
336  
337  
  /**
338  
   * Sets the number of items to fix at the top of the menu or popup menu.
339  
   * 
340  
   * @param topFixedCount the number of items
341  
   */
342  
  public void setTopFixedCount(int topFixedCount) {
343  
    if (firstIndex <= topFixedCount) {
344  
      firstIndex = topFixedCount;
345  
    } else {
346  
      firstIndex += (topFixedCount - this.topFixedCount);
347  
    }
348  
    this.topFixedCount = topFixedCount;
349  
  }
350  
351  
  /**
352  
   * Returns the number of items fixed at the bottom of the menu or popup menu.
353  
   * 
354  
   * @return the number of items
355  
   */
356  
  public int getBottomFixedCount() {
357  
    return bottomFixedCount;
358  
  }
359  
360  
  /**
361  
   * Sets the number of items to fix at the bottom of the menu or popup menu.
362  
   * 
363  
   * @param bottomFixedCount the number of items
364  
   */
365  
  public void setBottomFixedCount(int bottomFixedCount) {
366  
    this.bottomFixedCount = bottomFixedCount;
367  
  }
368  
369  
  /**
370  
   * Scrolls the specified item into view each time the menu is opened.  Call this method with
371  
   * <code>null</code> to restore the default behavior, which is to show the menu as it last
372  
   * appeared.
373  
   *
374  
   * @param item the item to keep visible
375  
   * @see #keepVisible(int)
376  
   */
377  
  public void keepVisible(JMenuItem item) {
378  
    if (item == null) {
379  
      keepVisibleIndex = -1;
380  
    } else {
381  
      int index = menu.getComponentIndex(item);
382  
      keepVisibleIndex = index;
383  
    }
384  
  }
385  
386  
  /**
387  
   * Scrolls the item at the specified index into view each time the menu is opened.  Call this
388  
   * method with <code>-1</code> to restore the default behavior, which is to show the menu as
389  
   * it last appeared.
390  
   *
391  
   * @param index the index of the item to keep visible
392  
   * @see #keepVisible(javax.swing.JMenuItem)
393  
   */
394  
  public void keepVisible(int index) {
395  
    keepVisibleIndex = index;
396  
  }
397  
398  
  /**
399  
   * Removes this JMenuScroller from the associated menu and restores the
400  
   * default behavior of the menu.
401  
   */
402  
  public void dispose() {
403  
    if (menu != null) {
404  
      menu.removePopupMenuListener(menuListener);
405  
      menu = null;
406  
    }
407  
  }
408  
409  
  /**
410  
   * Ensures that the <code>dispose</code> method of this JMenuScroller is
411  
   * called when there are no more refrences to it.
412  
   * 
413  
   * @exception  Throwable if an error occurs.
414  
   * @see JMenuScroller#dispose()
415  
   */
416  
  @Override
417  
  public void finalize() throws Throwable {
418  
    dispose();
419  
  }
420  
421  
  private void refreshMenu() {
422  
    if (menuItems != null && menuItems.length > 0) {
423  
      firstIndex = Math.max(topFixedCount, firstIndex);
424  
      firstIndex = Math.min(menuItems.length - bottomFixedCount - scrollCount, firstIndex);
425  
426  
      upItem.setEnabled(firstIndex > topFixedCount);
427  
      downItem.setEnabled(firstIndex + scrollCount < menuItems.length - bottomFixedCount);
428  
429  
      menu.removeAll();
430  
      for (int i = 0; i < topFixedCount; i++) {
431  
        menu.add(menuItems[i]);
432  
      }
433  
      if (topFixedCount > 0) {
434  
        menu.addSeparator();
435  
      }
436  
437  
      menu.add(upItem);
438  
      for (int i = firstIndex; i < scrollCount + firstIndex; i++) {
439  
        menu.add(menuItems[i]);
440  
      }
441  
      menu.add(downItem);
442  
443  
      if (bottomFixedCount > 0) {
444  
        menu.addSeparator();
445  
      }
446  
      for (int i = menuItems.length - bottomFixedCount; i < menuItems.length; i++) {
447  
        menu.add(menuItems[i]);
448  
      }
449  
450  
      JComponent parent = (JComponent) upItem.getParent();
451  
      parent.revalidate();
452  
      parent.repaint();
453  
    }
454  
  }
455  
456  
  private class MenuScrollListener implements PopupMenuListener {
457  
458  
    @Override
459  
    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
460  
      if (fillMenu != null) {
461  
        clearPopupMenu(menu);
462  
        callF(fillMenu, menu);
463  
      }
464  
      setMenuItems();
465  
    }
466  
467  
    @Override
468  
    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
469  
      if (fillMenu != null) clearPopupMenu(menu);
470  
      else restoreMenuItems();
471  
    }
472  
473  
    @Override
474  
    public void popupMenuCanceled(PopupMenuEvent e) {
475  
      if (fillMenu != null) clearPopupMenu(menu);
476  
      else restoreMenuItems();
477  
    }
478  
479  
    private void setMenuItems() {
480  
      menuItems = menu.getComponents();
481  
      if (keepVisibleIndex >= topFixedCount
482  
              && keepVisibleIndex <= menuItems.length - bottomFixedCount
483  
              && (keepVisibleIndex > firstIndex + scrollCount
484  
              || keepVisibleIndex < firstIndex)) {
485  
        firstIndex = Math.min(firstIndex, keepVisibleIndex);
486  
        firstIndex = Math.max(firstIndex, keepVisibleIndex - scrollCount + 1);
487  
      }
488  
      if (menuItems.length > topFixedCount + scrollCount + bottomFixedCount) {
489  
        refreshMenu();
490  
      }
491  
    }
492  
493  
    private void restoreMenuItems() {
494  
      menu.removeAll();
495  
      for (Component component : menuItems) {
496  
        menu.add(component);
497  
      }
498  
    }
499  
  }
500  
501  
  private class MenuScrollTimer extends javax.swing.Timer {
502  
503  
    public MenuScrollTimer(final int increment, int interval) {
504  
      super(interval, new ActionListener() {
505  
506  
        @Override
507  
        public void actionPerformed(ActionEvent e) {
508  
          firstIndex += increment;
509  
          refreshMenu();
510  
        }
511  
      });
512  
    }
513  
  }
514  
515  
  private class MenuScrollItem extends JMenuItem
516  
          implements ChangeListener {
517  
518  
    private MenuScrollTimer timer;
519  
520  
    public MenuScrollItem(MenuIcon icon, int increment) {
521  
      setIcon(icon);
522  
      setDisabledIcon(icon);
523  
      timer = new MenuScrollTimer(increment, interval);
524  
      addChangeListener(this);
525  
    }
526  
527  
    public void setInterval(int interval) {
528  
      timer.setDelay(interval);
529  
    }
530  
531  
    @Override
532  
    public void stateChanged(ChangeEvent e) {
533  
      if (isArmed() && !timer.isRunning()) {
534  
        timer.start();
535  
      }
536  
      if (!isArmed() && timer.isRunning()) {
537  
        timer.stop();
538  
      }
539  
    }
540  
  }
541  
542  
  static MenuIcon UP = new MenuIcon(9, 1, 9);
543  
  static MenuIcon DOWN = new MenuIcon(1, 9, 1);
544  
    
545  
  private sclass MenuIcon implements Icon {
546  
547  
    final int[] xPoints = {1, 5, 9};
548  
    final int[] yPoints;
549  
550  
    MenuIcon(int... yPoints) {
551  
      this.yPoints = yPoints;
552  
    }
553  
554  
    @Override
555  
    public void paintIcon(Component c, Graphics g, int x, int y) {
556  
      Dimension size = c.getSize();
557  
      Graphics g2 = g.create(size.width / 2 - 5, size.height / 2 - 5, 10, 10);
558  
      g2.setColor(Color.GRAY);
559  
      g2.drawPolygon(xPoints, yPoints, 3);
560  
      if (c.isEnabled()) {
561  
        g2.setColor(Color.BLACK);
562  
        g2.fillPolygon(xPoints, yPoints, 3);
563  
      }
564  
      g2.dispose();
565  
    }
566  
567  
    @Override
568  
    public int getIconWidth() {
569  
      return 0;
570  
    }
571  
572  
    @Override
573  
    public int getIconHeight() {
574  
      return 10;
575  
    }
576  
  }
577  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 8 computer(s): bhatertpkbcr, cfunsshuasjs, gwrvuhgaqvyk, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1020525
Snippet name: JMenuScroller
Eternal ID of this version: #1020525/9
Text MD5: 2ae482fbf35b849ee1f830d931eb7589
Transpilation MD5: 205532f784b2fce572766eba16759037
Author: stefan
Category: javax / gui
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-01-19 15:50:38
Source code size: 19267 bytes / 577 lines
Pitched / IR pitched: No / No
Views / Downloads: 374 / 1083
Version history: 8 change(s)
Referenced in: [show references]