How to trigger an action when clicking a disabled JMenuItem? - java

I did a bit of googling and poking around in SO but all examples are find are for cases when the JMenuItem is enabled.
Context for what I'm trying to do is that I want my disabled JMenuItem (because of limited privileges), when clicked, to display a pop up box requesting that the user upgrade so that they can access said JMenuItem.
The following is a stripped down version of what I currently have, nothing got printed out on the command line:
public class ExportMenuItem extends JMenuItem
{
public ExportMenuItem()
{
super("Menu Item Name");
addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent mouseEvent)
{
if (!isEnabled())
{
JOptionPane.showMessageDialog(editor.getFrame(), "Hello world.");
System.out.println("Sys print hello.");
}
System.out.println("Sys print hello outside.");
}
});
}
}

is this what you are looking for?
import javax.swing.*;
import java.awt.event.*;
public class ExportMenuItem extends JMenuItem{
public ExportMenuItem(){
super("menu item");
addMouseListener(new MouseListener(){
#Override
public void mouseClicked(MouseEvent mouseEvent){
if (!isEnabled()) {
JOptionPane.showMessageDialog(null, "Upgrade me!");
}//end of if
}//end of mouseClicked
public void mouseExited(MouseEvent mouseEvent){}
public void mouseEntered(MouseEvent mouseEvent){}
public void mouseReleased(MouseEvent mouseEvent){}
public void mousePressed(MouseEvent mouseEvent){}
// And the remaining methods to implement...
});//end of anonymous class
}//end of constructor
public static void main(String[] a){
JFrame f = new JFrame();
JMenu menu = new JMenu("menu");
JMenuBar menuBar = new JMenuBar();
f.setJMenuBar(menuBar);
f.setSize(300, 300);
f.setVisible(true);
menuBar.add(menu);
JMenuItem item = new ExportMenuItem();
menu.add(item);
item.setEnabled(false);
}//end of main
}//end of class

Maybe a complete different approach, that is more logical for users:
Place a describing text behind the menu item:
private void addRestartHint(JMenuItem m, String text) {
final String spaceholder = " ";
String t = m.getText() + spaceholder;
m.setLayout(new BorderLayout());
m.setText(t);
m.add(new JLabel(text), BorderLayout.EAST);
}

Related

How do you create an ActionListener for multiple JMenuItems?

I'm having difficulty using anonymous inner classes with actionListener. Can someone explain to me what is wrong with my code and how to use anonymous inner classes with actionListener. I'm trying to make a menu bar in one class and the action listener in the other. I ran into some difficulty when I tried using anonymous inner classes. The java website wasn't clear. Can you please explain it to me and help me fix my code.
public class Listener implements ActionListener {
HangmanView hangmanView = new HangmanView();
JFrame dialogFrame = new JFrame();
ImageIcon logo = new ImageIcon("logo.png");
public void listener1() {
hangmanView.getMenuItem().addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {// right click key
JOptionPane.showMessageDialog(dialogFrame, "Developer: Joe"
, "Developer",
JOptionPane.INFORMATION_MESSAGE, logo);
}// end actionPerformed method
});
}
}
another class:
public class HangmanView {
public JMenuItem getMenuItem() {
JMenuItem menuItem = new JMenuItem("Developer", KeyEvent.VK_T);
menuItem.addActionListener(new Listener());
return menuItem;
}
public JMenuBar menuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("File");
menuBar.add(menu);
menu.add(getMenuItem());// return here
return menuBar;
}
If you're trying to implement the listener for different JMenuItems, what I would do instead is create a custom Action class that you can use for multiple JMenuItems, as JMenuItems are a good example of when to use an Action.
private class MyAction extends AbstractAction {
String name;
public MyAction(String name, Icon icon) {
super(name, icon);
this.name = name;
}
public MyAction(String name, Icon icon, String desc,
Integer mnemonic, KeyStroke accelorator) {
super(name, icon);
putValue(Action.SHORT_DESCRIPTION, desc);
putValue(Action.MNEMONIC_KEY, mnemonic);
putValue(Action.ACCELERATOR_KEY, accelorator);
this.name = name;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (name) {
case "menu1Action":
// do something for menuItem1
break;
case "menu2Action":
// do something for menuItem2
break;
case "menu3Action":
// do something for menuItem3
break;
}
}
}
Have this class as an inner class of HangmanView. You can then create an instance of this custom Action class for each JMenuItem. Here's a example
Action menu1Action = new MyAction(
/* arg 1 */ "menu1Action",
/* arg 2 */ someIcon,
/* arg 3 */ "Some Short description of the action",
/* arg 4 */ new Integer(KeyEvent.VK_T),
/* arg 5 */ KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.CTRL_MASK));
The first argument is the name of the action. This name will be the name that you will see in the menu
The second argument is the icon that you will see in the menu next to the name.
The third argument is the Description of the menu item action
The fourth argument is the Mnemonic (i.e. Alt + T).
The fifth argument is the Accelerator (i.e. Ctrl + T).
When you add an Action to a JMenu, the title of that Action will automatically get placed as what you see in the JMenu. So all you need to do is add this custom Action to your JMenu. You don't ever have to actually create a JMenuItem at all. The Action will serve as the replacement for the JMenuItem. Just add all your MyAction objects to the JMenu.
menu.add(menu1Action);
What I have left out, is the implementation for each separate switch case in the actionPerformed. The case will be what you name the action in the constructor. Because I named the Action "menu1Action", I should have the corresponding name in the the switch case. In that case, you can do your JOptionPane or what ever else you wish to perform when that JMenuItem is clicked or accessed by keyboard.
Another great benefit of using an Action is that it can serve multiple purposes. With the same MyAction menu1Action you created, you can use the same Action for a JToolBar. Without any alteration to the above menu1Action, you could just do this:
JTooBar toolbar = new JToolBar();
toolbar.add(menu1Action);
Now in your tool bar and in your menu item, you have the same action. The tool bar will only show the icon and not the name.
Here is an example. What I do is create three different MyAction objects. One for left-alignment, one for center-alignment, and one for right-alignment. Each of these actions is used three separate times for three separate components, a menu item, a toll bar and a button
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionInterfaceDemo extends JFrame {
static JPanel buttonPanel = new JPanel();
static FlowLayout flowLayout = new FlowLayout();
public ActionInterfaceDemo(){
ImageIcon centerIcon = new ImageIcon(
ActionInterfaceDemo.class.getResource("image/centeralignment.png"));
ImageIcon rightIcon = new ImageIcon(
ActionInterfaceDemo.class.getResource("image/rightalignment.png"));
ImageIcon leftIcon = new ImageIcon(
ActionInterfaceDemo.class.getResource("image/leftalignment.png"));
Action leftAction = new MyAction("Left", leftIcon,
"Left alignment for the buttons in the panel",
new Integer(KeyEvent.VK_L),
KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.CTRL_MASK));
Action rightAction = new MyAction("Right", rightIcon,
"Right alignment for the buttons in the panel",
new Integer(KeyEvent.VK_R),
KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.CTRL_MASK));
Action centerAction = new MyAction("Center", centerIcon,
"Center alignment for the buttons in the panel",
new Integer(KeyEvent.VK_C),
KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
JMenuBar menuBar = new JMenuBar();
JMenu menuAlignment = new JMenu("Alignment");
setJMenuBar(menuBar);
menuBar.add(menuAlignment);
menuAlignment.add(leftAction);
menuAlignment.add(centerAction);
menuAlignment.add(rightAction);
JToolBar toolBar = new JToolBar("Alignment");
toolBar.setBorder(BorderFactory.createLineBorder(Color.BLUE));
toolBar.add(leftAction);
toolBar.add(centerAction);
toolBar.add(rightAction);
buttonPanel.setLayout(flowLayout);
JButton jbtLeft = new JButton(leftAction);
JButton jbtCenter = new JButton(centerAction);
JButton jbtRight = new JButton(rightAction);
buttonPanel.add(jbtLeft);
buttonPanel.add(jbtCenter);
buttonPanel.add(jbtRight);
add(toolBar, BorderLayout.EAST);
add(buttonPanel, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new ActionInterfaceDemo();
}
});
}
private class MyAction extends AbstractAction {
String name;
public MyAction(String name, Icon icon, String desc,
Integer mnemonic, KeyStroke accelorator) {
super(name, icon);
putValue(Action.SHORT_DESCRIPTION, desc);
putValue(Action.MNEMONIC_KEY, mnemonic);
putValue(Action.ACCELERATOR_KEY, accelorator);
this.name = name;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (name) {
case "Left":
flowLayout.setAlignment(FlowLayout.LEFT);
break;
case "Right":
flowLayout.setAlignment(FlowLayout.RIGHT);
break;
case "Center":
flowLayout.setAlignment(FlowLayout.CENTER);
break;
}
buttonPanel.revalidate();
}
}
}
You can press the "Left" in either the menu, the toolbar, or the button and they will produce the same result, as they are derived from the same Action.
Here are the images I used if you want to test it out
Note You don't have to use either of these exact constructors. You can create your own with different arguments. This is just a custom one I like to use.
Aslo See How to use Action tutorial
Listener, being an ActionListener through its inheritance hierarchy,
public class Listener implements ActionListener {
needs to implement an actionPerfomed(ActionEvent) method
#Override
public void actionPerformed(ActionEvent e) {
// implement it
}
However, since you seem to be adding an anonymous ActionListener, just don't have your Listener class implement ActionListener. Remove that bit.
Your object-oriented programming is all over the place. Your code in the OP looks like it's supposed to be some kind of GUI with different classes somehow working together but it's just creating new objects all over the place. There are too many reasons it doesn't work. I'd suggest you stick to something simple until you have a better grasp on how all this works.
You also got a very good suggestion in your other question that's a lot like this one but you haven't really followed it. Your code does something completely different.
Here is a very basic GUI. You have one object that has everything as fields. Everything is in one place. The containing object is the listener and decides what to do based on the event source. You should stick with a design like this until you are more comfortable with OOP.
public class HangmanView
implements ActionListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new HangmanView().setFrameVisible(true);
}
});
}
private JFrame theFrame = new JFrame("Main Window");
private JPanel theContent = new JPanel();
private JMenuBar theBar = new JMenuBar();
private JMenu fileMenu = new JMenu("File");
private JMenuItem exitMenuItem = new JMenuItem("Exit");
private JMenuItem devMenuItem = new JMenuItem("Developer");
public HangmanView() {
assert SwingUtilities.isEventDispatchThread();
exitMenuItem.addActionListener(this);
devMenuItem.addActionListener(this);
fileMenu.add(exitMenuItem);
theBar.add(fileMenu);
theBar.add(devMenuItem);
theContent.setPreferredSize(new Dimension(500, 500));
theFrame.setJMenuBar(theBar);
theFrame.setContentPane(theContent);
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theFrame.pack();
theFrame.setLocationRelativeTo(null);
}
public void setFrameVisible(boolean vis) {
theFrame.setVisible(vis);
}
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == devMenuItem) {
showDevDiag();
} else if(ae.getSource() == exitMenuItem) {
systemExit();
}
}
private void showDevDiag() {
JOptionPane.showMessageDialog(
theFrame,
"Developer: Joe",
"Developer",
JOptionPane.INFORMATION_MESSAGE,
null
);
}
private void systemExit() {
System.exit(0);
}
}
if I should use anonymous class, that's what should be done:
public static void main(String args[]){
/*bla bla bla...*/
JButton button1=new JButton("button1");
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae){
/*bla bla bla...*/
}
};
}
On the other hand, I always do this:
public class Class implements Runnable,ActionListener
{
private static Map<Thread,ActionEvent> THREAD_ATTRIB
=new HashMap<Thread,ActionEvent> (0);
JButton button1=new JButton("button1");
JButton button2=new JButton("button2");
//constructor
public Class(){
this.button1.addActionListener(this);
this.button2.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent ae){
Thread thread=new Thread(this);
THREAD_ATTRIB.put(thread,ae);
thread.start();
}
#Override
public void run(){
ActionEvent ae=THREAD_ATTRIB.get(Thread.currentThread());
if(ae!=null){
Object source=ae.getSource();
if(source.equals(this.button1){
/*bla bla bla...*/
} else if(source.equals(this.button2){
/*bla bla bla...*/
}
} else{
/*bla bla bla...*/
}
}
}

some questions about setMnemonic

I have the code:
public class MenuBar extends JFrame {
public MenuBar() {
initUI();
}
public final void initUI() {
JMenuBar menubar = new JMenuBar();
JMenu file = new JMenu("File");
file.setMnemonic(KeyEvent.VK_F);
JMenuItem eMenuItem = new JMenuItem("Exit");
JMenuItem oMenuItem = new JMenuItem("Open Another");
eMenuItem.setMnemonic(KeyEvent.VK_E);
oMenuItem.setMnemonic(KeyEvent.VK_O);
eMenuItem.setToolTipText("Exit application");
oMenuItem.setToolTipText("Open another Window");
eMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
oMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
main(null);
}
});
file.add(eMenuItem);
file.add(oMenuItem);
menubar.add(file);
setJMenuBar(menubar);
setTitle("Simple menu");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MenuBar ex = new MenuBar();
ex.setVisible(true);
}
});
}
}
it works fine but I had a question about setMnemonic. How would you go about making the Mnemonic for eMenuItem just to press E, as opposed to Alt + E? Thanks for any and all help! (Please not I left imports out intentially, for length issues)
From the docs of setMnemonic:
The mnemonic is the key which when combined with the look and feel's
mouseless modifier (usually Alt) will activate this button if focus is
contained somewhere within this button's ancestor window.
Thus using setMnemonic to do this is impossible.
However, you can use the setAccelerator method defined for JMenuItems, passing a keystroke like KeyStroke.getKeyStroke('e');
Alternatively, you could, as Joop Eggen pointed out in the comments to this answer use a MenuKeyListener which allows for greater control over the specific events that the action is performed on.
I don't know if this would work but you can try it out. From this (http://docs.oracle.com/javase/7/docs/api/constant-values.html#java.awt.event.KeyEvent.VK_E) we see that the ASCII binding for VK_E is 69. This is caps E. To get the one for small e its 101, which corresponds to VK_NUMPAD5. I might be wrong though, its just a guess.

How do I build a JMenu dynamically?

I am trying to build a JMenu dynamically right when clicking in it (I'm only getting an empty menu), below is my code.
final JMenu JMWindows = new JMenu("Opened Windows");
JMWindows.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(JInternalFrame ji : desktop.getAllFrames())
{
JMWindows.add(ji.getTitle());
}
}
});
I've realized that the actionperformed is never called, the JMenu is inside a JMenuBar. What could be the problem ?
You add ActionListener to JMenu this cannot be done for JMenu use MenuListener and set it via JMenu#addMenuListener(..)
Also you need to call revalidate() and repaint() on JMenu instance after adding/removing components from it or the changes will not be reflected (we could also call this on the containers instance i.e JMenuBar or JFrame, but we know only 1 specific JMenu will change so no need IMO).
Please watch your variable naming schemes JMWindow should be jmWindow/jMWindow variables always begin with no caps and the 1st letter of every new word thereafter gets capitalized (besides for constants and enums).
Here is an example using MenuListener:
import java.awt.*;
import java.awt.event.*;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
public class Test {
private JDesktopPane jdpDesktop;
private static int openFrameCount = 0;
final JFrame frame = new JFrame("JInternalFrame Usage Demo");
public Test() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// A specialized layered pane to be used with JInternalFrames
jdpDesktop = new JDesktopPane() {
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
};
for (int i = 0; i < 3; i++) {
createFrame(); // Create first window
}
frame.setContentPane(jdpDesktop);
frame.setJMenuBar(createMenuBar());
// Make dragging faster by setting drag mode to Outline
jdpDesktop.putClientProperty("JDesktopPane.dragMode", "outline");
frame.pack();
frame.setVisible(true);
}
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Frame");
menu.setMnemonic(KeyEvent.VK_N);
JMenuItem menuItem = new JMenuItem("New IFrame");
menuItem.setMnemonic(KeyEvent.VK_N);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
createFrame();
}
});
menu.add(menuItem);
menuBar.add(menu);
final JMenu jmWindows = new JMenu("Opened Windows");
jmWindows.addMenuListener(new MenuListener() {
#Override
public void menuSelected(MenuEvent me) {
jmWindows.removeAll();//remove previous opened window jmenuitems
for (JInternalFrame ji : jdpDesktop.getAllFrames()) {
JMenuItem menuItem = new JMenuItem(ji.getTitle());
jmWindows.add(menuItem);
}
jmWindows.revalidate();
jmWindows.repaint();
jmWindows.doClick();
}
#Override
public void menuDeselected(MenuEvent me) {
}
#Override
public void menuCanceled(MenuEvent me) {
}
});
menuBar.add(jmWindows);
return menuBar;
}
protected void createFrame() {
Test.MyInternalFrame frame = new Test.MyInternalFrame();
frame.setVisible(true);
// Every JInternalFrame must be added to content pane using JDesktopPane
jdpDesktop.add(frame);
try {
frame.setSelected(true);
} catch (java.beans.PropertyVetoException e) {
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
class MyInternalFrame extends JInternalFrame {
static final int xPosition = 30, yPosition = 30;
public MyInternalFrame() {
super("IFrame #" + (++openFrameCount), true, // resizable
true, // closable
true, // maximizable
true);// iconifiable
setSize(300, 300);
// Set the window's location.
setLocation(xPosition * openFrameCount, yPosition
* openFrameCount);
}
}
}
You need to repaint and or validate your frame after adding or removing something.
you can use the methods repaint() and validate() in your JFrame for this
You missed defining a JMenuItem.
final JMenu JMWindows = new JMenu("Opened Windows");
JMWindows.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(JInternalFrame ji : desktop.getAllFrames())
{
JMenuItem menuItem = new JMenuItem(ji.getTitle());
JMWindows.add(menuItem);
}
}
});

JMenuItem problem. I have five. One of them compiles with no problem. The others are identical, yet they refuse to compile

for some reason, I am unable to compile this in Eclipse. The "quit" menuItem works and no other menuItem works. Why is that?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUI{
private JFrame frame;
public GUI(){
makeFrame();
}
//This method makes the overall GUI and adds panels, labels,
//buttons, and everything else to the GUI.
public void makeFrame(){
frame = new JFrame("Tower Defense");
Container contentPane = frame.getContentPane();
makeMenus();
JButton shootButton = new JButton("Shoot");
contentPane.add(shootButton);
frame.pack();
frame.setVisible(true);
}
//This method makes the menu and all of the items contained
//in the menu which is then called by the makeFrame() method.
//I also add the menuItem's various ActionLiteners here.
public void makeMenus(){
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
JMenu fileMenu = new JMenu("File");
JMenu actionsMenu = new JMenu("Actions");
JMenu buildMenu = new JMenu("Build");
menubar.add(fileMenu);
menubar.add(actionsMenu);
menubar.add(buildMenu);
JMenuItem sellItem = new JMenuItem("Sell");
JMenuItem quitItem = new JMenuItem("Quit");
JMenuItem turretsItem = new JMenuItem("Turrets");
JMenuItem minesItem = new JMenuItem("Mines");
JMenuItem workersItem = new JMenuItem("Workers");
quitItem.addActionListener(new QuitActionListener());
sellItem.addActionListener(new SellActionListener());
turretsItem.addActionListener(new TurretsActionListener());
minesItem.addActionListener(new MinesActionListener());
workersItem.addActionListener(new WorkersActionListener());
fileMenu.add(quitItem);
actionsMenu.add(sellItem);
buildMenu.add(turretsItem);
buildMenu.add(minesItem);
buildMenu.add(workersItem);
}
//Main method. It creates a new GUI.
public static void main(String args []){
GUI gui = new GUI();
}
class QuitActionListener implements ActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
class SellActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
class TurretsActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
class MinesActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
class WorkersActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
class ShootActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
}
It is not compiling because the actions listeners (like SellActionListener, for example) that you are providing (all bar the quit action) are not implementing ActionListener. The method addActionListener expects an object that implements ActionListener.
This:
class SellActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
Needs to become this:
class SellActionListener implements ActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
(along with the other action listeners)
For posterity
These sort of errors can usually be figured out from the compiler feedback. When eclipse said that there were compile errors, you should be able to see the error details. I guess it would say something like "class SellActionListener does not implement the interface ActionListener" (or something along those lines). If you google that error message you might be able to find the answer faster that waiting for someone to answer your specific question.

How to create a JButton with a menu?

I want to create a Toolbar in my application. If you click a button on that toolbar, it will pop up a menu, just like in Eclipse's toolbar. I don't know how to do this in Swing. Can someone help me please? I've tried Google but found nothing.
This is way harder in Swing than it needs to be. So instead of pointing you to tutorials I've created a fully working example.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ToolbarDemo {
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(600, 400));
final JToolBar toolBar = new JToolBar();
//Create the popup menu.
final JPopupMenu popup = new JPopupMenu();
popup.add(new JMenuItem(new AbstractAction("Option 1") {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Option 1 selected");
}
}));
popup.add(new JMenuItem(new AbstractAction("Option 2") {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Option 2 selected");
}
}));
final JButton button = new JButton("Options");
button.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
popup.show(e.getComponent(), e.getX(), e.getY());
}
});
toolBar.add(button);
frame.getContentPane().add(toolBar, BorderLayout.NORTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I don't see why this is harder than it needs to be or why you should use a MouseListener. The solution by Steve McLeod works, but where the menu appears depends on where the mouse was clicked. Why not just use an ActionListener as normally used for a JButton. It seems neither harder nor less hard.
final JPopupMenu menu = new JPopupMenu();
menu.add(...whatever...);
final JButton button = new JButton();
button.setText("My Menu");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
menu.show(button, button.getBounds().x, button.getBounds().y
+ button.getBounds().height);
}
});
This positions the menu about the same as a menu in a JMenuBar for me, and the position is consistent. You could place it differently by modifying the x and y in menu.show().
Here is a simple and nice class
import javax.swing.JPopupMenu;
import javax.swing.JToggleButton;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class MenuButton extends JToggleButton {
JPopupMenu popup;
public MenuButton(String name, JPopupMenu menu) {
super(name);
this.popup = menu;
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
JToggleButton b = MenuButton.this;
if (b.isSelected()) {
popup.show(b, 0, b.getBounds().height);
} else {
popup.setVisible(false);
}
}
});
popup.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
MenuButton.this.setSelected(false);
}
#Override
public void popupMenuCanceled(PopupMenuEvent e) {}
});
}
}
I think it's the same as in AWT.
You should put an ActionCommand on that button and when it's executed show the pop-up menu according to the mouse coordinates.
See the section Bringing Up a Popup Menu, in How to Use Menus.
I'm not sure I understand you correctly but if you want to know how to make toolbars in Swing check this
Java Tutorials: How to Use Tool Bars and this
Java Tutorials: How to Use Actions
Above, Adam Goode asked,
Does your solution have the behavior where if you click the button again with the menu up, it pops up the menu again, instead of dismissing it?
This turned out to be a testing task. I finally solved it with an invokeLater to re-vanish the popup in that particular case. My solution also allows the client to tailor the button and the popup menu.
/**
* A button that will popup a menu.
* The button itself is a JLabel and can be adjusted with all
* label attributes. The popup menu is returned by getPopup;
* menu items must be added to it.
* <p>
* Clicks outside the menu will dismiss it.
*/
public class MenuButton extends JLabel
implements MouseListener, PopupMenuListener {
JPopupMenu popMenu;
#SuppressWarnings("")
public MenuButton() {
super();
popMenu = new JPopupMenu();
addMouseListener(this);
popMenu.addPopupMenuListener(this);
}
public JPopupMenu getPopup() { return popMenu; }
#Override
public void mousePressed(MouseEvent e) {
if ( ! popMenu.isShowing()) {
popMenu.show(this, 0, getBounds().height);
}
}
#Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
SwingUtilities.invokeLater(()->{
if (popMenu.isShowing()) {
// if shpwing, it was hidden and reshown
// by a mouse down in the 'this' button
popMenu.setVisible(false);
}
});
}
#Override public void mouseClicked(MouseEvent e) { }
#Override public void mouseReleased(MouseEvent e) { }
#Override public void mouseEntered(MouseEvent e) { }
#Override public void mouseExited(MouseEvent e) { }
#Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
#Override public void popupMenuCanceled(PopupMenuEvent e) { }
} // end MenuButton
Sample invocation
MenuButton button = new MenuButton();
JPopupMenu menu = button.getPopup();
menu.add("Browse Sample");
menu.add("Save As ...");
Icon hamburger = IOUtils.loadIconResource(
IndexGofer.class, "images/hamburgerMenu.png");
(IOUtils is on page http://physpics.com/Java/tools/
You should use your own tool to load an icon.)
button.setIcon(hamburger);
button.setOpaque(false);

Categories

Resources