Dynamic resizing of JMenu after adding items at runtime - java

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()

Related

Trying to create a MenuBar using Java.swing, and created an object of JMenu(), but it wont let me add It to the frame and not sure why?

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() );

Create Scroll Bar for JFrame

Hi I am trying to create Scroll Bar for my JFrame. I created JPanel object and set components into JPanel. Then created a JScrollPane object for the panel. Then add the ScrollPane object to JFrame. I am not seeing any scrollbar. Also I am wondering if there is a option in JPanel that would resize the object inside Jpanel automatically according to the zoom level of the JPanel. Any help would be highly appreciated.
public class xmlottgui {
private JPanel Container;
private JFrame frmCreateXml;
private JTextField titlename;
private JLabel lbltitlename;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
xmlottgui window = new xmlottgui();
window.frmCreateXml.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public xmlottgui() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
Container = new JPanel();
Container.setLayout(null);
//JScrollPane pane=new JScrollPane(Container,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
frmCreateXml = new JFrame();
frmCreateXml.setTitle("Create XML");
frmCreateXml.setBounds(100, 100, 1000, 1200);
frmCreateXml.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmCreateXml.getContentPane().setLayout(null);
//Create MenuBar
JMenuBar menuBar = new JMenuBar();
Container.add(menuBar);
JMenu mnFile = new JMenu("File");
menuBar.add(mnFile);
JMenuItem mntmImportFromCsv = new JMenuItem("Import From Excel File");
//Add menu item Exit
JMenuItem mntmexit = new JMenuItem("Exit");
mntmexit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
mnFile.add(mntmexit);
showform();
JScrollPane pane=new JScrollPane(Container,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane.setLayout(null);
frmCreateXml.setContentPane(pane);
frmCreateXml.getContentPane().add(pane);
}
private void showform(){
titlename = new JTextField();
titlename.setBounds(164, 27, 749, 26);
Container.add(titlename);
titlename.setColumns(10);
lbltitlename = new JLabel("Title Name");
lbltitlename.setBackground(Color.GRAY);
lbltitlename.setBounds(22, 1000, 90, 16);
Container.add(lbltitlename);
}
This:
pane.setLayout(null);
Will completely disable your JScrollPane and prevent it from working as it will prevent the JScrollPane from displaying and manipulating its view port properly. JScrollPanes have there own very special layout manager, one you never want to muck with unless you are very clever and know what you're doing. As a general rule you should almost never use null layouts.
Also this is not correct:
frmCreateXml.setContentPane(pane);
frmCreateXml.getContentPane().add(pane);
You make pane the contentPane and then add pane to itself.
AND THIS is messing you up:
frmCreateXml.getContentPane().setLayout(null);
You will want to learn about and use the layout managers as it will make your life much easier.

invisible JMenuBar, Accelerator not working

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.

Create jpanel in actionperformed listener?

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;
}

How to display a menu and a panel in the same window in Java Swing?

I've got a JMenu and I want to change the window's content according to what button from the menu is pressed. I managed to show the panel as a popup, but I want it to be displayed in the same window with the menu. This is my code so far :
public class GUImenu extends JFrame
{
private JMenuBar menuBar;
private JMenu menu;
private JMenu subMenu;
private JMenuItem item1;
private JMenuItem item2;
private JMenuItem item3;
private JMenuItem item4;
private JMenuItem item5;
private JMenuItem item6;
public GUImenu()
{
super("Example Menu System");// Call the JFrame constructor.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Specify an action for the close button.
buildMenuBar();
// Pack and display the window.
pack();
setSize(1000, 250); // set frame size
setVisible(true);
}
private void buildMenuBar()
{
// Create the menu bar.
menuBar = new JMenuBar();
// Create the file and text menus.
menu = new JMenu("Menu"); menuBar.add(menu);
subMenu = new JMenu("Create Customer");
item1 = new JMenuItem("Ordinary Customer"); subMenu.add(item1);
item1.addActionListener(new showOrdinaryCust());
item6 = new JMenuItem("Privileged Customer"); subMenu.add(item6);
menu.add(subMenu);
item2 = new JMenuItem("View Customers Who Didn't Pay"); menu.add(item2);
item3 = new JMenuItem("Remove Client");menu.add(item3);
item4 = new JMenuItem("Create Order"); menu.add(item4);
item5 = new JMenuItem("Search..."); menu.add(item5);
setJMenuBar(menuBar);
}
public static void main(String[] args)
{
new GUImenu();
}
private class showOrdinaryCust implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if(event.getSource()==item1)
GUIpanel.main(null);
}
}
}
I would try to fill the entire window with a CardLayout. CardLayout is meant to switch its contents between separate views. Simply set up multiple cards for each of the panels you want to show and have the menu switch between them.
If you use windows or dialogs you will latter have to deal with the focus, the closing, minimizing, maximizing, re-size, centering, visibility...
In your case i would recommend you to pick a good layout to suit your needs(Probably the easiest way to achieve your goal).
What do you think about tabbed panes?
See this link: http://docs.oracle.com/javase/tutorial/uiswing/components/tabbedpane.html
building guis is a little complex, but worth the time spent to understand what options are. This is a good place to start as it explains various java gui layouts, including using a layout manager. http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html.
For future posts, your example should be complete, including imports so we can copy and paste code, compile and look at.
It is simple enough. I have implemented this thing as follows :
First get content pane of your JFrame, say in container. Make this container object static.
private static Container container;
now get content pane.
container = this.getContentPane();
Now on click on menu call some method that will do some thing like this :
container.removeAll();
container.add(new JPanel()); //Add object of your panel you want to show.
container.revalidate();
This method is helpful in case you want to show multiple panels in same JFrame.

Categories

Resources