We know that we can invoke a menu item with the help of setaccelerator() method where a combination of two keystrokes are required. what if i want to invoke a menu item by just one keystroke...here is where i am having a bit problem
menuitem=new JMenuItem("Delete");
menuitem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE);
menu.add(menuitem);
Please help....!!
Check How to Use Menus for details. Below is an example that utilizes Action, that defines accelerator. You can also set accelerator on the menu item, ie: item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class MenuDemo {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
JMenuItem item = new JMenuItem(new TestAction(frame));
menu.add(item);
frame.setJMenuBar(menuBar);
frame.setSize(new Dimension(300, 300));
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
static class TestAction extends AbstractAction {
private Component parent;
public TestAction(Component parent) {
super("Test");
this.parent = parent;
putValue(Action.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
}
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(parent, "Test");
}
}
}
Related
My problem is about accelerators on JMenuItem, the accelerator doesn't work if the JMenu is not opened, but only for some of them. For one it is working (CTRL + G), but for another one it is not working (CTRL + H). I have no idea why it doesn't work.
(it's working if the JMenu is open I remind it)
Maybe it's about another shortcut already set up on that combination ?
remplacer.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_H, java.awt.event.InputEvent.CTRL_DOWN_MASK));
remplacer.setText("Remplacer");
remplacer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
remplacerActionPerformed(evt);
}
});
edition_menu.add(remplacer);
atteindre.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, java.awt.event.InputEvent.CTRL_DOWN_MASK));
atteindre.setText("Atteindre");
atteindre.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
atteindreActionPerformed(evt);
}
});
edition_menu.add(atteindre);
Here are two JMenuItem contained in a JMenu, one is working anyway, but the other is working only if I open the JMenu before. Thank's for your help.
Seems to work fine for me, consider providing a minimal reproducible example which demonstrates your issue
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JMenuItem replaceMI = new JMenuItem("Replace");
replaceMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK));
replaceMI.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Do replace");
}
});
JMenuItem findMI = new JMenuItem("Find");
findMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK));
findMI.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Do find");
}
});
JMenu editMenu = new JMenu("Edit");
editMenu.add(replaceMI);
editMenu.add(findMI);
JMenuBar menuBar = new JMenuBar();
menuBar.add(editMenu);
JFrame frame = new JFrame();
frame.setJMenuBar(menuBar);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
class MemberBook extends Frame {
MenuBar mb;
Menu menu;
MenuItem miReg, miList, miExit;
MemberBook() {
super();
mb = new MenuBar();
menu = new Menu("Menu");
miReg = new MenuItem("Register");
miList = new MenuItem("List");
miExit = new MenuItem("Exit");
menu.add(miReg);
menu.add(miList);
menu.addSeparator();
menu.add(miExit);
mb.add(menu);
setMenuBar(mb);
MenuHandler handler = new MenuHandler(this);
miReg.addActionListener(handler);
miList.addActionListener(handler);
miExit.addActionListener(handler);
setSize(300, 500);
setVisible(true);
}
public static void main(String args[]) {
MemberBook win = new MemberBook();
}
class MenuHandler implements ActionListener {
MemberBook frame;
// I want to add panel to outer class but I don't know
// other way to do it so, get _frame in constructor
MenuHandler(MemberBook _frame) {
frame = _frame;
}
// show different panels for each menu
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Register")) {
RegisterPanel panel = new RegisterPanel();
frame.add(panel, "Center");
}
// else if ...
}
}
// predefined panel to show in MemberBook frame
class RegisterPanel extends Panel {
}
}
I want to make pre defined member register panel, member list panel (you can see members list and edit members) and show when choose menu but RegisterPanel doesn't show when I choose register menu. I don't know other way to add panel to frame in inner Listener class, so transferred frame to Listener constructor.
So, the basic answer is, use a CardLayout, see How to Use CardLayout for more details.
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class MemberBook {
public static void main(String[] args) {
new MemberBook();
}
private JMenuBar mb;
private JMenu menu;
private JMenuItem miReg, miList, miExit;
public MemberBook() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
mb = new JMenuBar();
menu = new JMenu("Menu");
miReg = new JMenuItem("Register");
miList = new JMenuItem("List");
miExit = new JMenuItem("Exit");
menu.add(miReg);
menu.add(miList);
menu.addSeparator();
menu.add(miExit);
mb.add(menu);
MainPane mainPane = new MainPane();
MenuHandler handler = new MenuHandler(mainPane);
miReg.addActionListener(handler);
miList.addActionListener(handler);
miExit.addActionListener(handler);
JFrame frame = new JFrame();
frame.setJMenuBar(mb);
frame.add(mainPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface MemberBookController {
public void registerUser();
}
public class MainPane extends JPanel implements MemberBookController {
private CardLayout cardLayout;
public MainPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
add(new WelcomePane(), "welcome");
add(new RegisterPanel(), "register");
cardLayout.show(this, "welcome");
}
#Override
public void registerUser() {
cardLayout.show(this, "register");
}
}
public class MenuHandler implements ActionListener {
private MemberBookController controller;
// I want to add panel to outer class but I don't know
// other way to do it so, get _frame in constructor
MenuHandler(MemberBookController controller) {
this.controller = controller;
}
// show different panels for each menu
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Register")) {
controller.registerUser();
}
// else if ...
}
}
public class WelcomePane extends JPanel {
public WelcomePane() {
setBorder(new EmptyBorder(16, 16, 16, 16));
setLayout(new GridBagLayout());
add(new JLabel("Welcome"));
setBackground(Color.BLUE);
}
}
// predefined panel to show in MemberBook frame
public class RegisterPanel extends JPanel {
public RegisterPanel() {
setBorder(new EmptyBorder(16, 16, 16, 16));
setLayout(new GridBagLayout());
add(new JLabel("Register"));
setBackground(Color.RED);
}
}
}
This example also demonstrates the use of a interface to provide "information hiding". The MenuHandler doesn't really need access to the frame or base pane, in fact, it shouldn't care. All it needs to do is tell interested parties that some action has occurred.
I might consider using the Action API to do this, so you can isolate the functionality a little more, see How to Use Actions for more details.
Below is a complete compiling running failing example illustrating my question. JMenuItem extends JComponent. When added to JPopupMenu and shown in a context menu... it is... well... SHOWN, but the componentShown method is not called. How can I know when the JMenuItem is shown? I need to know from within the JMenuItem itself. I'm creating this JMenuItem and handing it off to a larger framework. I have no knowledge or control of the JPopupMenu, container, or any other components. When my JMenuItem is shown, I must update its text based on the context and current state of the app. How do I know when it is shown?
In the following example, the text "component shown" is never printed under any circumstances. Right click inside the JPanel to get the context menu and you'll see the JMenuItem text, "Reply Hi", but now output to the console.
I'm running on macOS 11.5.2 Big Sur and JDK 11.0.6 LTS (from Oracle).
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class JMenuItemListeners {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.setMinimumSize(new Dimension(800, 600));
panel.setLayout(new BorderLayout());
panel.add(new JLabel("Hello World... right click me."),
BorderLayout.CENTER);
//========================================
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem menuItem = new JMenuItem("Reply Hi");
menuItem.addComponentListener(
new ComponentListener() {
#Override
public void componentResized(ComponentEvent e) {}
#Override
public void componentMoved(ComponentEvent e) {}
#Override
public void componentShown(ComponentEvent e) {
System.out.println("component shown");
}
#Override
public void componentHidden(ComponentEvent e) {}
}
);
popupMenu.add(menuItem);
panel.setComponentPopupMenu(popupMenu);
//========================================
frame.setContentPane(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
You can use an AncestorListener:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class JMenuItemListeners {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.setMinimumSize(new Dimension(800, 600));
panel.setLayout(new BorderLayout());
panel.add(new JLabel("Hello World... right click me."),
BorderLayout.CENTER);
//========================================
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem menuItem = new JMenuItem("Reply Hi");
menuItem.addAncestorListener(new AncestorListener()
{
#Override
public void ancestorRemoved(AncestorEvent e) {}
#Override
public void ancestorMoved(AncestorEvent e) {}
#Override
public void ancestorAdded(AncestorEvent e) {
System.out.println("ancestor shown");
}
});
popupMenu.add(menuItem);
panel.setComponentPopupMenu(popupMenu);
//========================================
frame.setContentPane(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
I don't think that you'll find some kind of listener that is notified when a JMenuItem is shown.
I would instead try to decouple the JMenuItem from the state of your application and I would do that using a javax.swing.AbstractAction.
You can update the AbstractAction anytime the context and / or state of your application changes and magically when the JMenuItem is shown it will reflect the context and state of your application.
The code fragment below contains replaces the creation of the JPopupMenu and the JMenuItem. The second part shows how you would update the AbstractAction by turning the JMenuItem into a clock.
//========================================
JPopupMenu popupMenu = new JPopupMenu();
AbstractAction a = new AbstractAction("Reply Hi") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Hi");
}
};
JMenuItem menuItem = new JMenuItem(a);
popupMenu.add(menuItem);
panel.setComponentPopupMenu(popupMenu);
//========================================
Timer t = new Timer(100, (e) -> {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("'Its 'HH:mm:ss");
a.putValue(Action.NAME, dtf.format(LocalTime.now()));
});
t.start();
//========================================
I have written a small test program which creates a split pane in which one of the pane's is a text area. I have added a meubar and menuitems to the pane but i donot see them in the gui that is created.
Could anyone pls point out what the wrong thing did i do over here in the below program:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.JMenuBar;
import java.util.*;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.io.IOException;
//SplitPaneDemo itself is not a visible component.
public class SplitPaneDemo extends JFrame
implements ActionListener {
private JTextArea ta;
private JMenuBar menuB;
private JMenu dbM;
private JMenuItem cnadb,bsmdb,cdmdb;
private JLabel picture;
private JSplitPane splitPane;
public SplitPaneDemo() {
ta = new JTextArea(); //textarea
ta.setLineWrap(true);
ta.setWrapStyleWord(true);
ta.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent ke )
{
int code = ke.getKeyCode();
int modifiers = ke.getModifiers();
if(code == KeyEvent.VK_ENTER && modifiers == KeyEvent.CTRL_MASK)
{
System.out.println("cmd in table:");
}
}
});
JScrollPane taPane = new JScrollPane(ta);
picture = new JLabel();
picture.setFont(picture.getFont().deriveFont(Font.ITALIC));
picture.setHorizontalAlignment(JLabel.CENTER);
JScrollPane pictureScrollPane = new JScrollPane(picture);
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
taPane, pictureScrollPane);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation(450);
//Provide minimum sizes for the two components in the split pane.
Dimension minimumSize = new Dimension(100, 100);
taPane.setMinimumSize(minimumSize);
pictureScrollPane.setMinimumSize(minimumSize);
//Provide a preferred size for the split pane.
splitPane.setPreferredSize(new Dimension(900, 900));
menuB = new JMenuBar(); //menubar
dbM = new JMenu("DB"); //file menu
cnadb = new JMenuItem("CNA");
bsmdb = new JMenuItem("BSM");
cdmdb = new JMenuItem("CDM");
setJMenuBar(menuB);
menuB.add(dbM);
dbM.add(cnadb);
dbM.add(bsmdb);
dbM.add(cdmdb);
cnadb.addActionListener(this);
bsmdb.addActionListener(this);
cdmdb.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
}
public void valueChanged(ListSelectionEvent e) {
}
public JSplitPane getSplitPane() {
return splitPane;
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("SplitPaneDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SplitPaneDemo splitPaneDemo = new SplitPaneDemo();
frame.getContentPane().add(splitPaneDemo.getSplitPane());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
You add the JMenuBar in your SplitPaneDemo class, but when you actually call createAndShowGUI, you make a new JFrame and only add the SplitPane to it with the call to getSplitPane. This new frame has no knowledge of the menu bar.
If you are extending JFrame in SplitPaneDemo, why not use that to make the frame for your gui?
i am creating a desktop application in netbeans and i want that in my menu bar if i select a new menu item than o nly the below panel is change not full frame.so it will look like that i m working on a single frame.can anyone help me out
You can use Card Layout Managers to achieve such functionality.
Here is complete example:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
class JMenuExample extends JFrame implements ActionListener {
JMenu menu;
JPanel panelMain;
JPanel panelRed;
JPanel panelBlue;
CardLayout layout;
public void createUI() {
createMenu();
createPanels();
}
private void createPanels() {
panelMain = new JPanel();
layout = new CardLayout();
panelMain.setLayout(layout);
panelRed = new JPanel();
panelRed.setBackground(Color.RED);
panelMain.add(panelRed, "Red");
panelBlue = new JPanel();
panelBlue.setBackground(Color.BLUE);
panelMain.add(panelBlue, "Blue");
add(panelMain);
}
private void createMenu() {
menu = new JMenu("Change To");
JMenuItem miRed = new JMenuItem("Red");
miRed.addActionListener(this);
menu.add(miRed);
JMenuItem miBlue = new JMenuItem("Blue");
miBlue.addActionListener(this);
menu.add(miBlue);
JMenuBar bar = new JMenuBar();
bar.add(menu);
setJMenuBar(bar);
}
public static void main(String[] args) {
JMenuExample frame = new JMenuExample();
frame.createUI();
frame.setSize(150, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JMenuItem) {
JMenuItem mi = (JMenuItem) e.getSource();
layout.show(panelMain, mi.getText());
}
}
}
Hope this helps