I have 1 JFrame and 10 JPanel components as seperate classes. There is also JMenuBar on jframe. When a menu item clicked, i remove all content of contentPane of jframe (removeAll) and add one of my jpanels.
Here is my code;
// this function changes panel
public static void SwitchPanel(Component comp)
{
Container panel = getContentPane();
panel.removeAll();
panel.add(comp);
panel.revalidate();
panel.repaint();
}
// this function defines menu items and their listeners
public JMenuItem AddMenuItem(JMenu menu, String name, final JPanel toPanel) {
JMenuItem menuItem = new JMenuItem(name);
menu.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SwitchPanel(toPanel);
}
});
return menuItem;
}
and i add menu items like that;
AddMenuItem(menu1, "some menu item", new MyPersonalJPanel());
Everything works. BUT i want to create new jpanel when a related menu item clicked. I mean create jpanel if only it is necessary. Current code creates all jpanels first. When i clicked a menu item, shows me jpanel created before.
I think it can be done with Class.forName method, but i couldn't figure it out. Any help?
You should do the new MyPersonalJPanel() in the public void actionPerformed(ActionEvent e) method. That way the panel would be created each time the user click on the menu.
Your code would then be:
// this function defines menu items and their listeners
public JMenuItem AddMenuItem(JMenu menu, String name) {
JMenuItem menuItem = new JMenuItem(name);
menu.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SwitchPanel(new MyPersonalJPanel());
}
});
return menuItem;
}
Related
As in title, I struggle to get my JMenu to resize when programatically adding components. In my application I need JMenu with JCheckBoxes. Whenever I tick one of them, JSlider should appear just below. Below is the code that makes that happen. The problem I have is that when there's lot of sliders visible, items in JMenu get clumped - see image below.
How can I force redraw/resize/expansion of JMenu to perserve original checkboxes/sliders height?
Also note - JMenu stays visible at all times when selecting checkboxes. It closes only when I click outside of it. But after such 'restart' menu grows and problem is no longer present.
Many thanks in advance!
public class Window extends JFrame implements ActionListener {
private JPanel panel;
private JMenuBar menuBar;
private JMenu menu;
private JSlider slider1;
private JCheckBoxMenuItem checkBox1;
private JCheckBoxMenuItem checkBox2;
private JCheckBoxMenuItem checkBox3;
public Window() {
super("Example");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(300,300));
panel = new JPanel();
panel.setMinimumSize(new Dimension(300,300));
menuBar = new JMenuBar();
menu = new JMenu("Options");
checkBox1 = new JCheckBoxMenuItem("option 1");
checkBox2 = new JCheckBoxMenuItem("option 2");
checkBox3 = new JCheckBoxMenuItem("option 3");
checkBox1.addActionListener(this);
//prevent JMenu from closing after selecting CheckBox
checkBox1.setUI(new BasicCheckBoxMenuItemUI() {
#Override
protected void doClick(MenuSelectionManager msm) {
checkBox1.doClick(0);
}
});
slider1 = new JSlider();
slider1.setVisible(false);
menu.add(checkBox1);
menu.add(slider1);
menu.add(checkBox2);
menu.add(checkBox3);
menuBar.add(menu);
setJMenuBar(menuBar);
add(panel);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(checkBox1)) {
slider1.setVisible(checkBox1.isSelected());
}
}
}
Here's screen from my main application:
Hiding and reshowing the popup menu will cause it to be resized:
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(checkBox1)) {
slider1.setVisible(checkBox1.isSelected());
menu.setPopupMenuVisible(false);
menu.setPopupMenuVisible(true);
}
}
Call revalidate() it is supposed to do the trick, call it on the newly added components. https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Component.html#revalidate()
But i would say a use case like this is not what menus are meant for? why not use a dialog for dynamic components?
For background https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Component.html#revalidate() call it o the newly added component and see https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Component.html#invalidate() and https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Container.html#isValidateRoot()
public class Menu {
private JMenu borders;
//constructor
public Menu()
{
//crate object
//this.menuBar = new JMenuBar();
//------create menu items----
//menu item for borders
borders = new JMenu("Border");
// add border options
borders.setMnemonic(KeyEvent.VK_U);
//add border options
borders.add(new JMenuItem("Etched"));
borders.add(new JMenuItem("Raised"));
borders.add(new JMenuItem("Matte"));
borders.add(new JMenuItem("Tilted"));
borders.add(new JMenuItem("Compounded"));
JMenuItem quit = new JMenuItem("Quit");
quit.setMnemonic(KeyEvent.VK_Q);
borders.add(quit);
//set Accelerator
quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Event.CTRL_MASK));
//add action listener
//#Override
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
}
}
public class DrawingFrame extends JFrame{
protected CanvasEditor canvasEditor;
protected DrawingCanvas drawingCanvas;
private Menu menu;
public DrawingFrame()
{
this.setTitle("Drawing Application");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
drawingCanvas = new DrawingCanvas();
drawingCanvas.setMinimumSize(new Dimension(300,700));
this.add(drawingCanvas);
JPanel toolBarPanel = getToolBarPanel();
this.add(drawingCanvas,BorderLayout.CENTER);
this.add(toolBarPanel,BorderLayout.SOUTH);
//create menu from class
this.menu = new Menu();
//create menu bar
JMenuBar menuBar = new JMenuBar();
//add menu to menuBar
menuBar.add(menu);
error: cannot resolve method 'add'
not sure why it won't accept the add method
The drawingFrame class accepts objects from canvasEditor and DrawingCanvas but it doesn't accept objects from Menu class.
I want to create a menuBar and add a menu to it, and then have it on the same frame -- drawing Frame
pretty sure it's a simple fix, but not sure how to fix it
public class Menu {
private JMenu borders;
You create a class called Menu and create an instance of a JMenu in this class.
this.menu = new Menu();
//create menu bar
JMenuBar menuBar = new JMenuBar();
//add menu to menuBar
menuBar.add(menu);
You then create an instance of the Menu class and attempt to add it to the JMenuBar, which can't be done because the Menu class is NOT a Component.
Instead you want to add the borders variable to the menubar.
This means you need to create a method in your Menu class like:
public JMenu getJMenu()
{
return borders;
}
Then you use:
//menuBar.add(menu);
menuBar.add( menu.getJMenu() );
My Program has a JMenuBar with JMenuItems.
They have a ActionListener, and I set a Shortcut with setAccelerator.
Now I am hiding the menu bar when the window become unfocused, to get more space for a displayed image.
But after the first hiding of the menubar, the hotkeys just stop working.
How can I fix that?
I created a little example code to illustrate that strange behavior:
import javax.swing.*;
import java.awt.event.*;
class Example extends JFrame{
public static void main(String[] args) {
new Example(); //main is static
}
static JMenuBar menubar; //be accessable for the ActionListener
Example() {
//JPanel
this.setSize(50,50);
this.setVisible(true);
//Menubar, static
menubar = new JMenuBar();
this.setJMenuBar(menubar);
//Menu
JMenu filemenu = new JMenu("File");
menubar.add(filemenu);
//Item
JMenuItem menuitem = new JMenuItem("Do Something...");
filemenu.add(menuitem);
menuitem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.SHIFT_DOWN_MASK)); // Shift + D
menuitem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action!");
}
});
JButton button = new JButton("Show/Hide menubar");
this.add(button);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Toggle Bar!");
menubar.setVisible(!menubar.isVisible()); //Toggle
}
});
}
}
For reference:
I'm using Java 1.7.0_60-ea (Java 7) on a Mac.
But this error occurs independent of using the Mac native menu bar or the normal java menu bar inside the JFrame.
You could try to add global keybindings. How to add keybindings is explained here.
Here is an example of what you could do:
//Any component that is always visible in the window (like the image)
JComponent c;
//Get input and action map
InputMap imap = c.getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap amap = c.getActionMap();
//Put keybinding and action
imap.put(KeyStroke.getKeyStroke("shift D"), "doSomething");
amap.put("doSomething", anAction);
Note that it only works in the focused window. But should work regardless of the menubar being visible or not.
Simple question - I am editting a java based MMORPG game and wanted to add a menubar to the gameframe. So I did, but the menubar seems to cut into the game and block some of the content so that it is hidden behind the menubar. There is an example picture right here:
And here is a picture of my code:
public GameFrame(GameWindow gameWindow, int width, int height, String title, boolean resizable, boolean flag1) {
frameOffset = 28;
frameWidth = width;
frameHeight = height - 1;
aGameWindow = gameWindow;
addListeners(this, gameWindow);
if (flag1)
frameOffset = 48;
else
frameOffset = 28;
setTitle(title);
setResizable(resizable);
menubar = new MenuBar();
menu = new java.awt.Menu("Menu");
submenu = new java.awt.Menu("Sub Menu");
m1 = new MenuItem("Menu Item 1");
m2 = new MenuItem("Menu Item 2");
m3 = new MenuItem("Menu Item 3");
m4 = new MenuItem("Menu Item 4");
m5 = new MenuItem("Menu Item 5");
menu.add(m1);
menu.add(m2);
menu.add(m3);
submenu.add(m4);
submenu.add(m5);
menu.add(submenu);
menubar.add(menu);
setMenuBar(menubar);
this.addWindowListener(new WindowListener() {
#Override
public void windowActivated(WindowEvent arg0) {}
#Override
public void windowClosed(WindowEvent arg0) {
System.exit(-1);
}
#Override
public void windowClosing(WindowEvent arg0) {
System.exit(-1);
}
#Override
public void windowDeactivated(WindowEvent arg0) {}
#Override
public void windowDeiconified(WindowEvent arg0) {}
#Override
public void windowIconified(WindowEvent arg0) {}
#Override
public void windowOpened(WindowEvent arg0) {}
});
show();
toFront();
resize(frameWidth, frameHeight);
aGraphics49 = getGraphics();
}
Any ideas on how to fix this problem, or create some extra space up top so that it wont interfere with the game?
Thanks
Instead of a JMenuBar, just do a MenuBar. It will show a menu bar that is above the GUI and will allow your full screen of the GUI to be shown...it acts as a JMenuBar in every way..
MenuBar mB = new MenuBar();
Menu menu = new Menu("Menu");
MenuItem mI1 = new MenuItem("Menu Item 1");
// setting the bar
this.setMenuBar(mB);
//adding the menu onto the bar
mB.addMenu(menu);
// adding the menu item into the menu
menu.addMenuItem(mI1);
//adding action listener
mI1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do whatever
}
});
You can see much more here:
MenuBar, Menu, and MenuItem help
You could try creating a pause menu using a Jpanel. Every good game needs a pause menu :).
Make sure if you go this route give the JPanel a keyListener so you may setVisible when you press a determined key.
Looks like the game panel does not respect the insets.
instead of adding the menubar to the GameFrame itself, create a top level panel - put the GameFrame inside it at BorderLayout.CENTER and add the menubar to the top level panel.
then add that panel to your applet instead of adding the GameFrame directly.
The JMenuBar does not start showing JMenuItems as selected or displaying the JMenu popups until it is first clicked upon. After you click somewhere in the JMenuBar, all these items respond to mouse hovers.
I would like to bypass the initial click required and have it activated automatically upon a mouse hover. Is there a way to do this?
The way is to add a MouseListener on the JMenu and listen on events mouseEntered. In the event handlers, you just need to click on it using doClick. For example,
jMenuFile.addMouseListener(new MouseListener(){
public void mouseEntered(MouseEvent e) {
jMenuFile.doClick();
}
...
});
Once programmatically clicked on the mouse is entered, it opens the popup menu automatically. To activate an entire JMenuBar, you have to add a listener on each JMenu. For this purpose, it is better to create a listener object separately.
I have two menu items on the bar, so I did:
MouseListener ml = new MouseListener(){
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
((JMenu)e.getSource()).doClick();
}
};
jMenuFile.addMouseListener(ml);
jMenuHelp.addMouseListener(ml);
If you have so many menu items on the bar, you can just iterate it:
for (Component c: jMenuBar1.getComponents()) {
if (c instanceof JMenu){
c.addMouseListener(ml);
}
}
Roman C's initial and accepted answer will not AUTO Close the menu with child MenuItems as part of the JMenuBar.
Running a ((JMenu)e.getSource()).doClick(); on the mouseEntered simulates the click into one of the JMenu parents but can't be simply added to the mouseExited method as the MouseListener needs to be attached to the child MenuItems as well as the JMenu parents. (Which it doesn't do in the normal assignment to the MenuBar - only attaching to the parent JMenu objects).
Additionally, a problem arises due to trying to get the MouseExit listener to fire a "close" method ONLY when the mouse has left the entire Menu structure (ie the Child menu dropdowns).
Below is a fully working answer taken from my live app:
The way I solved the menu close on mouse out was to run a boolean variable "isMouseOut" in the top of the constructor to keep track, and then allocate the MouseListener in a more OO friendly way to keep track of the multiple MouseIn-MouseOut events as a user interacts with the menu. Which calls a separate menuClear method acting upon the state of the boolean "isMouseOut". The class implements MouseListener. This is how its done.
Create an ArrayList adding all the menu items to this array first. Like so:
Font menuFont = new Font("Arial", Font.PLAIN, 12);
JMenuBar menuBar = new JMenuBar();
getContentPane().add(menuBar, BorderLayout.NORTH);
// Array of MenuItems
ArrayList<JMenuItem> aMenuItms = new ArrayList<JMenuItem>();
JMenuItem mntmRefresh = new JMenuItem("Refresh");
JMenuItem mntmNew = new JMenuItem("New");
JMenuItem mntmNormal = new JMenuItem("Normal");
JMenuItem mntmMax = new JMenuItem("Max");
JMenuItem mntmStatus = new JMenuItem("Status");
JMenuItem mntmFeedback = new JMenuItem("Send Feedback");
JMenuItem mntmEtsyTWebsite = new JMenuItem("EtsyT website");
JMenuItem mntmAbout = new JMenuItem("About");
aMenuItms.add(mntmRefresh);
aMenuItms.add(mntmNew);
aMenuItms.add(mntmNormal);
aMenuItms.add(mntmMax);
aMenuItms.add(mntmStatus);
aMenuItms.add(mntmFeedback);
aMenuItms.add(mntmEtsyTWebsite);
aMenuItms.add(mntmAbout);
then iterate over the arrayList at this stage adding a MouseListener using the for() loop:
for (Component c : aMenuItms) {
if (c instanceof JMenuItem) {
c.addMouseListener(ml);
}
}
Now set JMenu parents for the MenuBar:
// Now set JMenu parents on MenuBar
final JMenu mnFile = new JMenu("File");
menuBar.add(mnFile).setFont(menuFont);
final JMenu mnView = new JMenu("View");
menuBar.add(mnView).setFont(menuFont);
final JMenu mnHelp = new JMenu("Help");
menuBar.add(mnHelp).setFont(menuFont);
Then add the dropdown menuItems children to the JMenu parents:
// Now set menuItems as children of JMenu parents
mnFile.add(mntmRefresh).setFont(menuFont);
mnFile.add(mntmNew).setFont(menuFont);
mnView.add(mntmNormal).setFont(menuFont);
mnView.add(mntmMax).setFont(menuFont);
mnHelp.add(mntmStatus).setFont(menuFont);
mnHelp.add(mntmFeedback).setFont(menuFont);
mnHelp.add(mntmEtsyTWebsite).setFont(menuFont);
mnHelp.add(mntmAbout).setFont(menuFont);
Add the mouseListeners to the JMenu parents as a separate step:
for (Component c : menuBar.getComponents()) {
if (c instanceof JMenu) {
c.addMouseListener(ml);
}
}
Now that the child menuItem elements all have their own listeners that are separate to the parent JMenu elements and the MenuBar itself - It is important to identify the object type within the MouseListener() instantiation so that you get the menu auto opening on mouseover (in this example the 3x JMenu parents) BUT ALSO avoids child exception errors and allows clean identification of mouseOUT of the menu structure without trying to monitor where the mouse position is. The MouseListener is as follows:
MouseListener ml = new MouseListener() {
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
isMouseOut = true;
timerMenuClear();
}
public void mouseEntered(MouseEvent e) {
isMouseOut = false;
Object eSource = e.getSource();
if(eSource == mnHelp || eSource == mnView || eSource == mnFile){
((JMenu) eSource).doClick();
}
}
};
The above only simulates the mouse click into the JMenu 'parents' (3x in this example) as they are the triggers for the child menu dropdowns. The timerMenuClear() method calls on the MenuSelectionManager to empty whatever selectedpath point was live at the time of real mouseOUT:
public void timerMenuClear(){
ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(isMouseOut == true){
System.out.println("Timer");
MenuSelectionManager.defaultManager().clearSelectedPath();
}
}
};
//Delay timer half a second to ensure real mouseOUT
Timer timer = new Timer(1000, task);
timer.setInitialDelay(500);
timer.setRepeats(false);
timer.start();
}
It took me a little testing, monitoring what values I could access within the JVM during its development - but it Works a treat! even with nested menus :) I hope many find this full example very useful.