JPopupMenu

  • Thread starter Richard A. DeVenezia
  • Start date
R

Richard A. DeVenezia

How do I respond to menu selections ?

I have FigurePanel, which is a subclass of JPanel. The constructor calls
init() which is

public class FigurePanel extends javax.swing.JPanel implements
java.io.Serializable, MouseListener, MouseMotionListener {
/*stuff*/

JPopupMenu cutMenu;

void init (double llx, double lly, double urx, double ury) {
/*stuff*/
cutMenu = new JPopupMenu();
cutMenu.add(new JMenuItem("Cut"));
cutMenu.add(new JMenuItem("Cancel"));
}

public void mouseClicked(MouseEvent e) {
/*stuff*/
cutMenu.show(e.getComponent(),e.getX(),e.getY());
/*stuff*/
}

The menu appears and I can select Cut or Cancel or click somewhere off the
menu and the menu goes away.

I don't know how to have my panel respond to
Cut selected
Cancel selected
Menu lost focus (do same thing as Cancel)
.....

I tried
cutMenu.add(new JMenuItem("Cut")).addActionListener(thsi);
but the compiler barked
addActionListener(java.awt.event.ActionListener) in
javax.swing.AbstractButton cannot be applied to (FigurePanel)


I would love to be able to simply do
JMenuItem selected = cutMenu.show(e.getComponent(),e.getX(),e.getY());
but that is not in the cards.

Thanks
 
C

Carl

Richard said:
How do I respond to menu selections ?

I have FigurePanel, which is a subclass of JPanel. The constructor calls
init() which is

public class FigurePanel extends javax.swing.JPanel implements
java.io.Serializable, MouseListener, MouseMotionListener {
/*stuff*/

JPopupMenu cutMenu;

void init (double llx, double lly, double urx, double ury) {
/*stuff*/
cutMenu = new JPopupMenu();
cutMenu.add(new JMenuItem("Cut"));
cutMenu.add(new JMenuItem("Cancel"));
}

public void mouseClicked(MouseEvent e) {
/*stuff*/
cutMenu.show(e.getComponent(),e.getX(),e.getY());
/*stuff*/
}

The menu appears and I can select Cut or Cancel or click somewhere off the
menu and the menu goes away.

I don't know how to have my panel respond to
Cut selected
Cancel selected
Menu lost focus (do same thing as Cancel)
....

I tried
cutMenu.add(new JMenuItem("Cut")).addActionListener(thsi);
but the compiler barked
addActionListener(java.awt.event.ActionListener) in
javax.swing.AbstractButton cannot be applied to (FigurePanel)


I would love to be able to simply do
JMenuItem selected = cutMenu.show(e.getComponent(),e.getX(),e.getY());
but that is not in the cards.

Thanks

FigurePanel should implement ActionListener before registering it as an
ActionListener. You must also include the ActionPerformed(ActionEvent e)
method. Query the ActionEvent object for the button that was pressed.

HTH.
 
C

Chris Smith

Hi Richard,
How do I respond to menu selections ?

You add an ActionListener to the menu item.
I tried
cutMenu.add(new JMenuItem("Cut")).addActionListener(thsi);
but the compiler barked
addActionListener(java.awt.event.ActionListener) in
javax.swing.AbstractButton cannot be applied to (FigurePanel)

There are a couple problems there:

First, you are adding the ActionListener to the wrong thing. Rather
than adding the listener to the entire popup menu, you want to add it to
a specific menu item. Thus,

JMenuItem cutItem = new JMenuItem("Cut");
JMenuItem cancelItem = new JMenuItem("Cancel");

cutMenu.add(cutItem);
cutMenu.add(cancelItem);

cutItem.addActionListener(...);
cancelItem.addActionListener(...);

Second, the thing you're adding needs to actually *be* an
ActionListener. The easiest way to do this for very trivial cases is to
use an anonymous inner class, so the last two lines of code above
become:

cutItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
...
}
});

cancelItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
...
}
});

If the code in those anonymous classes gets larger, though, you'll want
to move them to named classes, and end up with:

cutItem.addActionListener(new CutActionHandler());
cancelItem.addActionListener(new CancelActionHandler());

For mid-range cases where you don't want to use an anonymous class, but
don't want to create a named class either, you can have an anonymous
inner class delegate to a method in the outer class. I find this to be
a decent compromise in many situations, and do it quite a bit:

cutItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
cut();
}
});

cancelItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
cancel();
}
});

then later,

private void cut()
{
...
}

private void cancel()
{
...
}
I don't know how to have my panel respond to
Cut selected
Cancel selected
Menu lost focus (do same thing as Cancel)

The method-delegation above is particularly nice here because you've
expressed a desire to re-use the cancel code in another context from the
same outer class. So you could also do this:

cutMenu.addPopupMenuListener(new PopupMenuListener() {
public void popupMenuCanceled(PopupMenuEvent e)
{
cancel();
}

...
});

(At the ellipse, you'll need to also implement the other listener
methods from PopupMenuListener, because there quite inexplicably seems
to be no PopupMenuAdapter class in Swing.)
I would love to be able to simply do
JMenuItem selected = cutMenu.show(e.getComponent(),e.getX(),e.getY());
but that is not in the cards.

No, it's not. GUI development is done in an event-driven environment.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

Carl said:
FigurePanel should implement ActionListener before registering it as an
ActionListener. You must also include the ActionPerformed(ActionEvent e)
method. Query the ActionEvent object for the button that was pressed.

That's one way to do it. It's generally considered a bad idea, though.
Even if you do it that way, it needs actionPerformed(ActionEvent), not
ActionPerformed(ActionEvent).

The better direction is to move FigurePanel away from implementing any
listener interfaces at all. Having a class implement a listener
interface constitutes an invitation to add it as a listener to arbitrary
other components; when that's not a sensible thing to do, the interface
in that class's API is misleading.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Carl

Chris said:
That's one way to do it. It's generally considered a bad idea, though.
Even if you do it that way, it needs actionPerformed(ActionEvent), not
ActionPerformed(ActionEvent).

Point well taken on the typo.
Your example is clearly a better solution in the end, I was simply trying to
make an example that would easily 'blend' the code provided (already
implementing interfaces, etc.), which the original poster seems to already
have an understanding of.
The better direction is to move FigurePanel away from implementing any
listener interfaces at all. Having a class implement a listener
interface constitutes an invitation to add it as a listener to arbitrary
other components; when that's not a sensible thing to do, the interface
in that class's API is misleading.

Although I agree with what I *think* your argument in this statement, I
can't say I fully understand it. I certainly don't believe that this
example "constitutes" any relationship with any "arbitrary" component ;^) .
Even if the interface is implemented, it's still a 'FigurePanel', and never
claims to be an "arbitraryComponentListener", at least not any more than
the javax.swing.JComboBox does, right?

Cheers,
Carl.
 
C

Chris Smith

Carl said:
Although I agree with what I *think* your argument in this statement, I
can't say I fully understand it. I certainly don't believe that this
example "constitutes" any relationship with any "arbitrary" component ;^) .

Okay, so arbitrary was the wrong word. Clearly, any class will have a
specific purpose that's described in its documentation, and can't be
applied arbitrarily. However, I do think that implementing the listener
interface (which *is* a part of the classes public API) constitutes an
implication that the class is intended to be registered as a listener by
*external* code... something that is misleading in this context.
Even if the interface is implemented, it's still a 'FigurePanel', and never
claims to be an "arbitraryComponentListener", at least not any more than
the javax.swing.JComboBox does, right?

I'll agree with the part about "any more than JComboBox does".
JComboBox is an example of this kind of sloppy treatment of public API,
made even worse by its being not only public, but published and very
widely distributed. In other words, I think JComboBox is an example of
a poor programming technique.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
A

Andrew Thompson

| How do I respond to menu selections ?
|
| I have FigurePanel, which is a subclass of JPanel. The
constructor calls
| init() which is

Why do you use init() as the name of a
method in a panel? It is too easy to
confuse with applets.

| public class FigurePanel extends javax.swing.JPanel implements
| java.io.Serializable, MouseListener, MouseMotionListener {
| /*stuff*/

Please do not supply 'snippets'. That 'stuff'
you cut may or may not be the important bit,
I suggest you prepare an example.
http://www.physci.org/codes/sscce.jsp
 
R

Richard A. DeVenezia

Chris Smith said:
Hi Richard,
snippety

For mid-range cases where you don't want to use an anonymous class, but
don't want to create a named class either, you can have an anonymous
inner class delegate to a method in the outer class. I find this to be
a decent compromise in many situations, and do it quite a bit:

Thanks for the help. I totally spaced needing ActionListener.
I took your advice and went for the 'intermediate' form (method-delegation)
that uses an inner
class to dispatch the response to the event.
First, you are adding the ActionListener to the wrong thing. Rather
than adding the listener to the entire popup menu, you want to add it to
a specific menu item.

JMenuItem.add() returns a JMenuItem, so I can suffix with
..addActionListener(<whatever>).

cutMenu.add(new JMenuItem("Cut"))
.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){ cut(); }
});
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top