Search code examples
javaswinginterfacemenubarjmenu

Expand JMenu to left, while retaining default text alignment


I have a JMenu A within a JMenuBar aligned to the right of the screen. Within this menu are several JMenuItems, along with another JMenu B. Since menu A is right aligned, I need menu B to open to the left. In order to do this I found the code

setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);.

The issue however, is that this messes with the text alignment of menu 2, which I would like to stay exactly like the other menu items.

Example

I have also tried manually aligning menu 2 using SwngConstants.leftAlign, however this is too severe:

enter image description here

How can I make the menu expand to the left, while retaining the default text alignment? Thanks in advance! The code I used to produce the above images is seen below:

import java.awt.*;
import javax.swing.*;

public class Test{  
    public Test(){
        JFrame frame = new JFrame();
        JMenuBar menuBar = new JMenuBar();
        JMenu menu1 = new JMenu("Menu 1");
        JMenu menu2 = new JMenu("Menu 2");
        JMenuItem menuitem1 = new JMenuItem("Menu Item 1");
        JMenuItem menuitem2 = new JMenuItem("Menu Item 2");
        JMenuItem menuitem3 = new JMenuItem("Menu Item 3");
        JMenuItem menuitem4 = new JMenuItem("Menu Item 4");

        menuBar.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        menu1.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        menu2.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        menu2.setHorizontalAlignment(SwingConstants.LEFT);

        menuBar.add(menu1);
        menu1.add(menuitem1);
        menu1.add(menuitem2);
        menu1.add(menu2);
        menu2.add(menuitem3);
        menu2.add(menuitem4);

        frame.setJMenuBar(menuBar);
        frame.getContentPane().setBackground(Color.WHITE);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(270,170));
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args){
        try{
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                UIManager.getLookAndFeelDefaults().put("Label.font", new Font("Arial", Font.PLAIN, 12));
                UIManager.getLookAndFeelDefaults().put("Button.font", new Font("Arial", Font.PLAIN, 12));
                UIManager.getLookAndFeelDefaults().put("ComboBox.font", new Font("Arial", Font.PLAIN, 12));
                UIManager.getLookAndFeelDefaults().put("JTextField.font", new Font("Arial", Font.PLAIN, 12));
            new Test();
        } catch(Exception e){
            JOptionPane.showConfirmDialog(null, e.getMessage());
        }
    }
}

UPDATE: If I remove the lines of code aligning the menus right to left and move the frame to the edge of the display screen, then the menus act as desired (i.e. the menu will not expand off the monitor). Perhaps there is a way to tell the menu not to expand off the JFrame rather than the monitor?

UPDATE: Thank you @StanislavL for the idea. Overriding menu 2 with the following code does the trick, it also gets rid of that unsightly overlap between the two menus. Note that menu 2 no longer needs ComponentOrientation.RIGHT_TO_LEFT.

JMenu menu2 = new JMenu("Menu 2"){
    protected Point getPopupMenuOrigin(){
        return new Point(-this.getPopupMenu().getPreferredSize().width, 0);
    }
};

Solution

  • You can try to override

    public ComponentOrientation getComponentOrientation()
    

    method of JMenu to return your alignmnet

    or JMenu has method you can override

    protected Point getPopupMenuOrigin()