epubjs
Version:
Render ePub documents in the browser, across many devices
192 lines (172 loc) • 26.3 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Pop-Up Menus</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Pop-Up Menus"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-17-SECT-8"/>Pop-Up Menus</h1></div></div></div><p><a id="idx10986" class="indexterm"/> <a id="idx11001" class="indexterm"/> One of Swing’s nifty components is <a id="I_indexterm17_id796605" class="indexterm"/><code class="literal">JPopupMenu</code>, a context
menu that appears at the mouse location when you press the appropriate
mouse button or keystroke. (On a two-button mouse, clicking the right
mouse button invokes a pop-up menu. On a single-button Mac, you
Command-click.) Which button you press depends on the platform you’re
using; fortunately, from the code’s point of view you don’t have to
care—Swing figures it out for you.</p><p>The care and feeding of <code class="literal">JPopupMenu</code> is basically the same as any other
menu. You use a different constructor—<code class="literal">JPopupMenu()</code>—to create it, but otherwise, you
build a menu and add elements to it the same way. The big difference is
that you don’t attach it to a <code class="literal">JMenuBar</code>.
Instead, just pop up the menu whenever and wherever you need it. Prior to
Java 5.0, this process is a little cumbersome; you have to register to
receive the appropriate mouse events, check them to see if they are the
pop-up trigger and then pop the menu manually. With Java 5.0, the process
is simplified by having components manage their own pop-up menus.</p><p>First, we’ll show an example of explicit pop-up handling. The
following example, <code class="literal">PopupColorMenu</code>,
contains three buttons. You can use a <code class="literal">JPopupMenu</code> to set the color of each button or
the background frame itself, depending on where you click the
mouse.</p><a id="I_17_tt1030"/><pre class="programlisting"> <code class="c1">//file: PopUpColorMenu.java</code>
<code class="kn">import</code> <code class="nn">java.awt.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.awt.event.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.swing.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">PopUpColorMenu</code> <code class="kd">implements</code> <code class="n">ActionListener</code>
<code class="o">{</code>
<code class="n">Component</code> <code class="n">selectedComponent</code><code class="o">;</code>
<code class="kd">public</code> <code class="nf">PopUpColorMenu</code><code class="o">()</code> <code class="o">{</code>
<code class="n">JFrame</code> <code class="n">frame</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JFrame</code><code class="o">(</code><code class="s">"PopUpColorMenu v1.0"</code><code class="o">);</code>
<code class="kd">final</code> <code class="n">JPopupMenu</code> <code class="n">colorMenu</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JPopupMenu</code><code class="o">(</code><code class="s">"Color"</code><code class="o">);</code>
<code class="n">colorMenu</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">makeMenuItem</code><code class="o">(</code><code class="s">"Red"</code><code class="o">));</code>
<code class="n">colorMenu</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">makeMenuItem</code><code class="o">(</code><code class="s">"Green"</code><code class="o">));</code>
<code class="n">colorMenu</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">makeMenuItem</code><code class="o">(</code><code class="s">"Blue"</code><code class="o">));</code>
<code class="n">MouseListener</code> <code class="n">mouseListener</code> <code class="o">=</code> <code class="k">new</code> <code class="n">MouseAdapter</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">mousePressed</code><code class="o">(</code><code class="n">MouseEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code> <code class="n">checkPopup</code><code class="o">(</code><code class="n">e</code><code class="o">);</code> <code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">mouseClicked</code><code class="o">(</code><code class="n">MouseEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code> <code class="n">checkPopup</code><code class="o">(</code><code class="n">e</code><code class="o">);</code> <code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">mouseReleased</code><code class="o">(</code><code class="n">MouseEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code> <code class="n">checkPopup</code><code class="o">(</code><code class="n">e</code><code class="o">);</code> <code class="o">}</code>
<code class="kd">private</code> <code class="kt">void</code> <code class="nf">checkPopup</code><code class="o">(</code><code class="n">MouseEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="k">if</code> <code class="o">(</code><code class="n">e</code><code class="o">.</code><code class="na">isPopupTrigger</code><code class="o">())</code> <code class="o">{</code>
<code class="n">selectedComponent</code> <code class="o">=</code> <code class="n">e</code><code class="o">.</code><code class="na">getComponent</code><code class="o">();</code>
<code class="n">colorMenu</code><code class="o">.</code><code class="na">show</code><code class="o">(</code><code class="n">e</code><code class="o">.</code><code class="na">getComponent</code><code class="o">(),</code> <code class="n">e</code><code class="o">.</code><code class="na">getX</code><code class="o">(),</code> <code class="n">e</code><code class="o">.</code><code class="na">getY</code><code class="o">());</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="o">};</code>
<code class="n">Container</code> <code class="n">content</code> <code class="o">=</code> <code class="n">frame</code><code class="o">.</code><code class="na">getContentPane</code><code class="o">();</code> <code class="c1">// unnecessary in 5.0+</code>
<code class="n">content</code><code class="o">.</code><code class="na">setLayout</code><code class="o">(</code><code class="k">new</code> <code class="n">FlowLayout</code><code class="o">());</code>
<code class="n">JButton</code> <code class="n">button</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JButton</code><code class="o">(</code><code class="s">"Uno"</code><code class="o">);</code>
<code class="n">button</code><code class="o">.</code><code class="na">addMouseListener</code><code class="o">(</code><code class="n">mouseListener</code><code class="o">);</code>
<code class="n">content</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">button</code><code class="o">);</code>
<code class="n">button</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JButton</code><code class="o">(</code><code class="s">"Due"</code><code class="o">);</code>
<code class="n">button</code><code class="o">.</code><code class="na">addMouseListener</code><code class="o">(</code><code class="n">mouseListener</code><code class="o">);</code>
<code class="n">content</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">button</code><code class="o">);</code>
<code class="n">button</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JButton</code><code class="o">(</code><code class="s">"Tre"</code><code class="o">);</code>
<code class="n">button</code><code class="o">.</code><code class="na">addMouseListener</code><code class="o">(</code><code class="n">mouseListener</code><code class="o">);</code>
<code class="n">content</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">button</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">getContentPane</code><code class="o">().</code><code class="na">addMouseListener</code><code class="o">(</code><code class="n">mouseListener</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setSize</code><code class="o">(</code><code class="mi">200</code><code class="o">,</code><code class="mi">50</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setDefaultCloseOperation</code><code class="o">(</code> <code class="n">JFrame</code><code class="o">.</code><code class="na">EXIT_ON_CLOSE</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setVisible</code><code class="o">(</code><code class="kc">true</code><code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">actionPerformed</code><code class="o">(</code><code class="n">ActionEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="n">String</code> <code class="n">color</code> <code class="o">=</code> <code class="n">e</code><code class="o">.</code><code class="na">getActionCommand</code><code class="o">();</code>
<code class="k">if</code> <code class="o">(</code><code class="n">color</code><code class="o">.</code><code class="na">equals</code><code class="o">(</code><code class="s">"Red"</code><code class="o">))</code>
<code class="n">selectedComponent</code><code class="o">.</code><code class="na">setBackground</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">red</code><code class="o">);</code>
<code class="k">else</code> <code class="nf">if</code> <code class="o">(</code><code class="n">color</code><code class="o">.</code><code class="na">equals</code><code class="o">(</code><code class="s">"Green"</code><code class="o">))</code>
<code class="n">selectedComponent</code><code class="o">.</code><code class="na">setBackground</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">green</code><code class="o">);</code>
<code class="k">else</code> <code class="nf">if</code> <code class="o">(</code><code class="n">color</code><code class="o">.</code><code class="na">equals</code><code class="o">(</code><code class="s">"Blue"</code><code class="o">))</code>
<code class="n">selectedComponent</code><code class="o">.</code><code class="na">setBackground</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">blue</code><code class="o">);</code>
<code class="o">}</code>
<code class="kd">private</code> <code class="n">JMenuItem</code> <code class="nf">makeMenuItem</code><code class="o">(</code><code class="n">String</code> <code class="n">label</code><code class="o">)</code> <code class="o">{</code>
<code class="n">JMenuItem</code> <code class="n">item</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JMenuItem</code><code class="o">(</code><code class="n">label</code><code class="o">);</code>
<code class="n">item</code><code class="o">.</code><code class="na">addActionListener</code><code class="o">(</code> <code class="k">this</code> <code class="o">);</code>
<code class="k">return</code> <code class="n">item</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code><code class="o">[]</code> <code class="n">args</code><code class="o">)</code> <code class="o">{</code>
<code class="k">new</code> <code class="nf">PopUpColorMenu</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">}</code></pre><p><a class="xref" href="ch17s07.html#learnjava3-CHP-17-FIG-8" title="Figure 17-8. The PopupColorMenu application">Figure 17-8</a> shows the example in
action; the user is preparing to change the color of the bottom
button.</p><div class="figure"><a id="learnjava3-CHP-17-FIG-8"/><div class="figure-contents"><div class="mediaobject"><a id="I_17_tt1031"/><img src="httpatomoreillycomsourceoreillyimages1707660.png.jpg" alt="The PopupColorMenu application"/></div></div><p class="title">Figure 17-8. The PopupColorMenu application</p></div><p>Because the pop-up menu is triggered by mouse events (in this
example), we need to register a <code class="literal">MouseListener</code> for any of the components to which
it applies. In this example, all three buttons and the content pane of the
frame are eligible for the color pop-up menu. Therefore, we add a mouse
event listener for all these components explicitly. The same instance of
an anonymous inner <code class="literal">MouseAdapter</code>
subclass is used in each case. In this class, we override the <a id="I_indexterm17_id796733" class="indexterm"/><code class="literal">mousePressed()</code>,
<a id="I_indexterm17_id796743" class="indexterm"/><code class="literal">mouseReleased()</code>, and
<a id="I_indexterm17_id796754" class="indexterm"/><code class="literal">mouseClicked()</code> methods to
display the pop-up menu when we get an appropriate event. How do we know
what an “appropriate event” is? Fortunately, we don’t need to worry about
the specifics of our user’s platform; we just need to call the event’s
<a id="I_indexterm17_id796769" class="indexterm"/><code class="literal">isPopupTrigger()</code> method.
If this method returns <code class="literal">true</code>, we know
the user has done whatever normally displays a pop-up menu on his
system.</p><p>Once we know that the user wants to raise a pop-up menu, we display
it by calling its <a id="I_indexterm17_id796790" class="indexterm"/><code class="literal">show()</code> method with the
mouse event coordinates as arguments.</p><p>If we want to provide different menus for different types of
components or the background, we create different mouse listeners for each
different kind of component. The mouse listeners invoke different kinds of
pop-up menus as appropriate.</p><p>The only thing left is to handle the action events from the pop-up
menu items. We use a helper method called <code class="literal">makeMenuItem()</code> to register the <code class="literal">PopUpColorMenu</code> window as an action listener for
every item we add. The example implements <code class="literal">ActionListener</code> and has the required <code class="literal">actionPerformed()</code> method. This method reads the
action command from the event, which is equal to the selected menu item’s
label by default. It then sets the background color of the selected
component appropriately.</p><div class="sect2" title="Component-Managed Pop Ups"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-17-SECT-9"/>Component-Managed Pop Ups</h2></div></div></div><p>Things get a bit easier in Java 5.0, using the new pop-up menu API
for components. In Java 5.0, any <code class="literal">JComponent</code> can manage a <code class="literal">JPopupMenu</code> directly with the <a id="I_indexterm17_id796854" class="indexterm"/><code class="literal">setComponentPopupMenu()</code>
method. <code class="literal">JComponent</code>s can also be told
to simply inherit their parent container’s pop-up menu via the
<a id="I_indexterm17_id796872" class="indexterm"/><code class="literal">setInheritsPopupMenu()</code>
method. This combination makes it very simple to implement a context
menu that should appear in many components within a container.</p><p>Unfortunately, this doesn’t lend itself well to our previous
example (<code class="literal">PopupColorMenu</code>) for two
reasons. First, we need to know which component the mouse was in when
the pop up was triggered and we don’t get that information using this
API. The pop-up handling is actually delegated to the container, not
inherited. Second, not all types of components are registered to receive
mouse events by default.<sup>[<a id="learnjava3-CHP-17-FNOTE-1" href="#ftn.learnjava3-CHP-17-FNOTE-1" class="footnote">40</a>]</sup> As a result, we’ll create a new example that is more
appropriate for a “one context menu to rule them all” application. The
following example, <code class="literal">ContextMenu</code>, shows
a <code class="literal">TextArea</code> and <code class="literal">TextField</code> that both inherit the same <code class="literal">JPopupMenu</code> from their <code class="literal">JPanel</code> container. When you select a menu item,
the action is displayed in the text area.</p><a id="I_17_tt1032"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.awt.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.awt.event.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.swing.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">ContextMenu</code> <code class="kd">implements</code> <code class="n">ActionListener</code>
<code class="o">{</code>
<code class="n">JTextArea</code> <code class="n">textArea</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JTextArea</code><code class="o">();</code>
<code class="kd">public</code> <code class="nf">ContextMenu</code><code class="o">()</code>
<code class="o">{</code>
<code class="kd">final</code> <code class="n">JPopupMenu</code> <code class="n">contextMenu</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JPopupMenu</code><code class="o">(</code><code class="s">"Edit"</code><code class="o">);</code>
<code class="n">contextMenu</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">makeMenuItem</code><code class="o">(</code><code class="s">"Save"</code><code class="o">));</code>
<code class="n">contextMenu</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">makeMenuItem</code><code class="o">(</code><code class="s">"Save As"</code><code class="o">));</code>
<code class="n">contextMenu</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">makeMenuItem</code><code class="o">(</code><code class="s">"Close"</code><code class="o">));</code>
<code class="n">JFrame</code> <code class="n">frame</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JFrame</code><code class="o">(</code><code class="s">"ContextMenu v1.0"</code><code class="o">);</code>
<code class="n">JPanel</code> <code class="n">panel</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JPanel</code><code class="o">();</code>
<code class="n">panel</code><code class="o">.</code><code class="na">setLayout</code><code class="o">(</code> <code class="k">new</code> <code class="n">BorderLayout</code><code class="o">()</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">getContentPane</code><code class="o">(</code> <code class="o">).</code><code class="na">add</code><code class="o">(</code> <code class="n">panel</code> <code class="o">);</code>
<code class="n">panel</code><code class="o">.</code><code class="na">setComponentPopupMenu</code><code class="o">(</code> <code class="n">contextMenu</code> <code class="o">);</code>
<code class="n">textArea</code><code class="o">.</code><code class="na">setInheritsPopupMenu</code><code class="o">(</code> <code class="kc">true</code> <code class="o">);</code>
<code class="n">panel</code><code class="o">.</code><code class="na">add</code><code class="o">(</code> <code class="n">BorderLayout</code><code class="o">.</code><code class="na">CENTER</code><code class="o">,</code> <code class="n">textArea</code> <code class="o">);</code>
<code class="n">JTextField</code> <code class="n">textField</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JTextField</code><code class="o">();</code>
<code class="n">textField</code><code class="o">.</code><code class="na">setInheritsPopupMenu</code><code class="o">(</code> <code class="kc">true</code> <code class="o">);</code>
<code class="n">panel</code><code class="o">.</code><code class="na">add</code><code class="o">(</code> <code class="n">BorderLayout</code><code class="o">.</code><code class="na">SOUTH</code><code class="o">,</code> <code class="n">textField</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setDefaultCloseOperation</code><code class="o">(</code> <code class="n">JFrame</code><code class="o">.</code><code class="na">EXIT_ON_CLOSE</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setSize</code><code class="o">(</code><code class="mi">400</code><code class="o">,</code><code class="mi">200</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setVisible</code><code class="o">(</code><code class="kc">true</code><code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">actionPerformed</code><code class="o">(</code> <code class="n">ActionEvent</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">textArea</code><code class="o">.</code><code class="na">append</code><code class="o">(</code> <code class="n">e</code><code class="o">.</code><code class="na">getActionCommand</code><code class="o">()</code> <code class="o">+</code><code class="s">"\n"</code> <code class="o">);</code>
<code class="o">}</code>
<code class="kd">private</code> <code class="n">JMenuItem</code> <code class="nf">makeMenuItem</code><code class="o">(</code><code class="n">String</code> <code class="n">label</code><code class="o">)</code> <code class="o">{</code>
<code class="n">JMenuItem</code> <code class="n">item</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JMenuItem</code><code class="o">(</code><code class="n">label</code><code class="o">);</code>
<code class="n">item</code><code class="o">.</code><code class="na">addActionListener</code><code class="o">(</code> <code class="k">this</code> <code class="o">);</code>
<code class="k">return</code> <code class="n">item</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code><code class="o">[]</code> <code class="n">args</code><code class="o">)</code> <code class="o">{</code>
<code class="k">new</code> <code class="nf">ContextMenu</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>We’ve constructed our <code class="literal">JPopupMenu</code> as before, but this time we are not
responsible for listening for mouse clicks or triggering the pop up
explicitly. Instead, we use the <a id="I_indexterm17_id796992" class="indexterm"/><code class="literal">setComponentPopupMenu()</code>
method to ask the <code class="literal">JPanel</code> to handle it
for us. We use <a id="I_indexterm17_id797009" class="indexterm"/><code class="literal">setInheritsPopupMenu()</code>
on both the <code class="literal">JTextArea</code> and <code class="literal">JTextField</code> so that they will both delegate
pop-up trigger mouse clicks to the <code class="literal">JPanel</code> automatically.<a id="I_indexterm17_id797036" class="indexterm"/><a id="I_indexterm17_id797044" class="indexterm"/></p></div><div class="footnotes"><br/><hr/><div class="footnote"><p><sup>[<a id="ftn.learnjava3-CHP-17-FNOTE-1" href="#learnjava3-CHP-17-FNOTE-1" class="para">40</a>] </sup>Components such as <code class="literal">JPanel</code>
and <code class="literal">JLabel</code> by default do not
expect to handle mouse events. When you register a listener such as
<code class="literal">MouseListener</code>, it registers
itself internally to begin processing these events. Unfortunately,
at the time of this writing, using <code class="literal">setInheritsPopupMenu()</code> does not trigger
this functionality. As a workaround, you could register a dummy
mouse listener with these components to prompt them to expect mouse
events and properly trigger context menus if you want them.</p></div></div></div></body></html>