使用JMenuBar、JMenu和JMenuItem自设计菜单栏时,会出现奇怪的呈现。

时间:2023-01-27 00:12:15

I wanted to design a translucent menubar, including menu and menu item, so I used JMenuBar, JMenu and JMenuItem to complete the code. That means my codes I just like to following one.

我想设计一个半透明的menubar,包括菜单和菜单项,所以我使用JMenuBar、JMenu和JMenuItem来完成代码。那意味着我的代码,我只是喜欢下面的。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
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.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.plaf.basic.BasicMenuItemUI;
import javax.swing.plaf.basic.BasicMenuUI;

public class Library extends JFrame {

    private int FRAME_WIDTH = SizeCtrl.mainFrameSizeCtrl().width;                                   // Main frame's width
    private int FRAME_HEIGHT = SizeCtrl.mainFrameSizeCtrl().height;                                 // Main frame's height

    private String title = "Library Management System?";                                                // System name
    private String copyright = "<html><b>Designer: RyougiChan &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
            + "Email : ryougi.chan.fire@gmail.com<br/></b></html>";                                 // copyright in bottom
    private String libImgURL = "res\\Library.jpg";
    private String mLogoURL = "res\\ryougi_logo.png";                                               // designer logo
    private String sLogoURL = "res\\LMS.png";                                                       // Systen logo
    private String[] manage = new String[] {"Books M", "Personel M", "Other M", "System M"};        // text of menu
    private String[] bookMng = new String[] {"borrow", " remand ", "buy", "donate ", "search"};     // text of menu items
    private String[] userMng = new String[] {"operator", "student", "teacher"};
    private String[] otherMng = new String[] {"authority", "fine"};
    private String[] sysMng = new String[] {"Message", "Update"};

    private Toolkit toolkit = Toolkit.getDefaultToolkit();;                         // Get system tookit
    private final int SCREEN_WIDTH = toolkit.getScreenSize().width;                 // Get current screen width
    private final int SCREEN_HEIGHT = toolkit.getScreenSize().height;               // Get current screen height

    private Color bgColor = new Color(0, 0, 0, 0.25f);                              // Background color most used
    private Color fgColor = Color.WHITE;                                            // Foreground color most used
    private JPanel rootPanel;                                                       // Create a root panel
    private JMenuBar jMenuBar;                                                      // A menu bar
    private JMenu menu;                                                             // menus on menu bar
    private JMenuItem menuItem;                                                     // items on menu
    private JPanel bodyPanel;                                                       // A panel below the menu bar
    private JPanel mlogo, slogo;                                                    // two logo container
    private JPanel footPanel;                                                       // The last panel on root panel
    private JLabel footLabel;                                                       // label on foot panel

    private MenuMouseAdapter menuAdapter;                                           // mouse event listener
    private MenuItemMouseAdapter menuItemAdapter;                                   // mouse event listener

    public void initModule() {
        /*
         * RyougiModule is a class to include all of my self-define module
         * RyougiModule.ImagePanel() is a panel to show a panel with background image
         * RyougiModule.NoticeLabel() is a label which can set properties of font, bounds and etc.
         */
        rootPanel = RyougiModule.ImagePanel(this, libImgURL, FRAME_WIDTH, FRAME_HEIGHT-30, 0, 0);
        jMenuBar = new MainMenuBar();
        bodyPanel = new JPanel();
        footPanel = new JPanel();
        footLabel = RyougiModule.NoticeLabel(footPanel, copyright, 16, null, fgColor);
    }

    public Library() {
        super();
        frameSizeCtrl();
        setTitle(title);
        setLocation(LocationCtrl.mainFrameLocationCtrl());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(null);

        initModule();
        rootPanel.setLayout(null);
        rootPanel.setBackground(Color.PINK);
        addBodyPanel();
        addBodyDetail();
        addFootPanel();
        add(rootPanel);
        setJMenuBar(addMenuBar());

        setResizable(false);
    }

    /**
     * Add a menu bar, and add menu into it.
     * @return Return a menu bar with specific style.
     */
    public JMenuBar addMenuBar() {
         jMenuBar.setBackground(bgColor);
         jMenuBar.setBorder(null);
         jMenuBar.setPreferredSize(new Dimension(getWidth(), 40));

         for (int i = 0; i < manage.length; i++) {
            String s = manage[i];
            addMenu(s);
            switch (i) {
            case 0:
                addMenuItem(bookMng);
                break;
            case 1:
                addMenuItem(userMng);
                break;
            case 2:
                addMenuItem(otherMng);
                break;
            case 3:
                addMenuItem(sysMng);
                break;
            default:
                break;
            }
        }

        return jMenuBar;
    }
    /**
     * Add menu into menu bar
     * @param s Text to display on menu
     */
    public void addMenu (String s) {
        menu = new JMenu(s);
        menuAdapter = new MenuMouseAdapter(menu, bgColor, fgColor);
        menu.setBorder(null);
        menu.setBackground(bgColor);
        menu.setForeground(fgColor);
        menu.addMouseListener(menuAdapter);
        jMenuBar.add(menu);
    }
    /**
     * Add menu item to menu to display a drop down menu
     * @param s Text to show on menu items
     */
    public void addMenuItem (String[] s) {
        for (int j = 0; j < s.length; j++) {
            menuItem = new JMenuItem(s[j]);
            menuItemAdapter = new MenuItemMouseAdapter(menuItem, bgColor, fgColor);
            menuItem.setBackground(bgColor);
            menuItem.setForeground(Color.BLUE);
            menuItem.setBorder(null);
            menuItem.setPreferredSize(new Dimension(60, 40));
            menu.add(menuItem);
        }
    }
    /**
     * Add panel below the menu bar
     * Including twoLogo
     */
    public void addBodyPanel() {
        bodyPanel.setLayout(null);
        bodyPanel.setPreferredSize(new Dimension(getWidth(), getHeight() - 30 - getWidth()*57/800));
        bodyPanel.setBackground(new Color(1.0f, 1.0f, 1.0f, 0.25f));
        bodyPanel.setForeground(null);
        bodyPanel.setBounds(0, 0, FRAME_WIDTH, FRAME_HEIGHT-110);
        rootPanel.add(bodyPanel);
    }
    /**
     * Add two logo to body panel
     */
    public void addBodyDetail() {
        int MLogoX = FRAME_WIDTH * 19/25,  MLogoY = 30,                         // Location of mLogo;
             SLogoX =FRAME_WIDTH * 13/20, SLogoY = FRAME_HEIGHT * 10/15;        // Location of sLogo;
        mlogo = new ImagePanel(mLogoURL, FRAME_WIDTH * 5/24, FRAME_WIDTH * 5/91, MLogoX, MLogoY);   // ?????logo
        bodyPanel.add(mlogo);
        slogo = new ImagePanel(sLogoURL, FRAME_WIDTH * 5/16, FRAME_WIDTH * 5/64, SLogoX, SLogoY);
        bodyPanel.add(slogo);

    }
    /**
     * Add panel in bottom to display the copyright message
     * Including a Jlabel to show message
     */
    public void addFootPanel() {
        footPanel.setBackground(new Color(0, 0, 0, 0));
        footPanel.setForeground(null);
        footLabel.setBackground(null);
        footLabel.setForeground(fgColor);
        footPanel.setBounds(0, FRAME_HEIGHT-110, FRAME_WIDTH,40);
        footPanel.add(footLabel);
        rootPanel.add(footPanel);
    }   
    /**
     * Control the size of frame
     */
    public void frameSizeCtrl() {
        Dimension dimension = SizeCtrl.mainFrameSizeCtrl();
        setSize(dimension);
    }
}

class MenuItemMouseAdapter extends MouseAdapter {

    private JMenuItem menuItem;
    private MenuItemUI menuItemUI;

    public MenuItemMouseAdapter(JMenuItem menuItem, Color bgColor, Color fgColor) {
        this.menuItem = menuItem;
        menuItemUI = new MenuItemUI(bgColor, fgColor);
        MenuItemExitedUI exitedUI = new MenuItemExitedUI();
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        System.out.println("Entered");
        menuItem.setUI(menuItemUI);
        menuItem.setBorder(null);
    }

    @Override
    public void mouseExited(MouseEvent e) {
        System.out.println("Exited");
        menuItem.setUI(null);
        menuItem.setUI(menuItemUI);
        menuItem.setBorder(null);
    }

}

class MenuMouseAdapter extends MouseAdapter {

    private JMenu menu;
    private MenuUI menuUI;

    public MenuMouseAdapter(JMenu menu, Color bgColor, Color fgColor) {
        this.menu = menu;
        this.menuUI = new MenuUI(bgColor, fgColor);
    }

    @Override
    public void mouseEntered(MouseEvent e) {
         menu.setUI(menuUI);
         menu.setBorder(null);
    }
}

class ImagePanel extends JPanel {

    private Toolkit toolkit = Toolkit.getDefaultToolkit();
    private String imgURL = "res\\ryougi_img.png";
    private int imgWidth, imgHeight, x, y;

    public ImagePanel(String imgURL, int imgWidth, int imgHeight, int x, int y) {
        this.imgURL = imgURL;
        this.imgWidth = imgWidth;
        this.imgHeight = imgHeight;
        this.setBounds(x, y, imgWidth, imgHeight);
        setBackground(new Color(0, 0, 0, 0));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Image img = toolkit.getImage(imgURL);
        g.drawImage(img, 0, 0, imgWidth, imgHeight, this);
    }
}

class MainMenuBar extends JMenuBar {

    private Toolkit toolkit = Toolkit.getDefaultToolkit();
    private String imgURL = "res\\library_top.jpg";

    public MainMenuBar() {
        this.setForeground(Color.WHITE);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Image img = toolkit.getImage(imgURL);
        g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
    }
}

class RyougiModule {

    private static Color LIGHT_BLUE_COLOR = new Color(120, 150, 232);               // 系统主题颜色
    private static JPanel tPanel;                                                   // 带标签的输入框面板
    private static JLabel tLabel;
    private static JTextField tField;

    private static JPanel pPanel;                                                   // 带标签的密码输入框面板
    private static JLabel pLabel;
    private static JPasswordField pField;

    private static JPanel imgPanel;                                                 // 带背景的面板
    private static JButton colorBtn;                                                // 带颜色按钮
    private static JLabel nLabel;                                                   // 带颜色文本

    private static JTextArea tArea;                                             // 文本区域

    /**
     * 带标签的文本输入框,标签颜色和输入框颜色 --> Color(120, 150, 232)
     * @param c 父组件
     * @param label 标签显示的文本
     * @param text 输入框显示的文本
     * @param x 当父布局 setLayout(null) 时,重新定位组件的水平位置
     * @param y 当父布局 setLayout(null) 时,重新定位组件的垂直位置
     */
    public static JPanel TextFieldWithLabel(JComponent c, String label, String text, int fontSize, int x, int y) {

        tPanel = new JPanel();
        tLabel = new JLabel(label);
        tField = new JTextField(text);
        tLabel.setForeground(LIGHT_BLUE_COLOR);
        tLabel.setFont(new Font("", Font.BOLD, fontSize));

        tField.setPreferredSize(new Dimension(180, 30));
        tField.setBorder(BorderFactory.createEtchedBorder(LIGHT_BLUE_COLOR, LIGHT_BLUE_COLOR));
        tField.setForeground(LIGHT_BLUE_COLOR);
        tField.setBackground(null);

        tPanel.setBounds(x, y, 280, 40);

        tPanel.add(tLabel);
        tPanel.add(tField);

        return tPanel;
    }
    /**
     * 带标签的文本输入框,标签颜色和输入框颜色 --> Color(120, 150, 232)
     * @param c 父组件
     * @param label 标签显示的文本
     * @param text 输入框显示的文本
     */
    public static JPanel TextFieldWithLabel(JComponent c, String label, String text, int fontSize) {

        tPanel = new JPanel();
        tLabel = new JLabel(label);
        tField = new JTextField(text);
        tLabel.setForeground(LIGHT_BLUE_COLOR);
        tLabel.setFont(new Font("", Font.BOLD, fontSize));

        tField.setPreferredSize(new Dimension(180, 30));
        tField.setBorder(BorderFactory.createEtchedBorder(LIGHT_BLUE_COLOR, LIGHT_BLUE_COLOR));
        tField.setForeground(LIGHT_BLUE_COLOR);
        tField.setBackground(null);

        tPanel.add(tLabel);
        tPanel.add(tField);

        return tPanel;
    }
    /**
     * 带标签的密码输入框,标签颜色和输入框颜色 --> Color(120, 150, 232)
     * @param c 父组件
     * @param label 标签显示的文本
     * @param text 输入框显示的文本
     * @param x 当父布局 setLayout(null) 时,重新定位组件的水平位置
     * @param y 当父布局 setLayout(null) 时,重新定位组件的垂直位置
     */
    public static JPanel PasswordFieldWithLabel(JComponent c, String label, String text, int fontSize, int x, int y) {

        pPanel = new JPanel();
        pLabel = new JLabel(label);
        pField = new JPasswordField(text);
        pLabel.setForeground(LIGHT_BLUE_COLOR);
        pLabel.setFont(new Font("", Font.BOLD, fontSize));

        pField.setPreferredSize(new Dimension(180, 30));
        pField.setBorder(BorderFactory.createEtchedBorder(LIGHT_BLUE_COLOR, LIGHT_BLUE_COLOR));
        pField.setForeground(LIGHT_BLUE_COLOR);
        pField.setBackground(null);

        pPanel.setBounds(x, y, 240, 40);

        pPanel.add(pLabel);
        pPanel.add(pField);
        return pPanel;
    }
    /**
     * 带标签的密码输入框,标签颜色和输入框颜色 --> Color(120, 150, 232) 浅蓝色
     * @param c 父组件
     * @param label 标签显示的文本
     * @param text 输入框显示的文本
     */
    public static JPanel PasswordFieldWithLabel(JComponent c, String label, String text, int fontSize) {
        pPanel = new JPanel();
        pLabel = new JLabel(label);
        pField = new JPasswordField(text);
        pLabel.setForeground(LIGHT_BLUE_COLOR);
        pLabel.setFont(new Font("", Font.BOLD, fontSize));

        pField.setPreferredSize(new Dimension(180, 30));
        pField.setBorder(BorderFactory.createEtchedBorder(LIGHT_BLUE_COLOR, LIGHT_BLUE_COLOR));
        pField.setForeground(LIGHT_BLUE_COLOR);
        pField.setBackground(null);

        pPanel.add(pLabel);
        pPanel.add(pField);
        return pPanel;
    }
    /**
     * 图片背景面板,加载背景图片等情况使用
     * @param c 父组件
     * @param imgURL 图片的存放路径
     * @param imgWidth 设置图片宽度
     * @param imgHeight 设置图片高度
     * @param x 设置图片水平位置
     * @param y 设置图片垂直位置
     */
    public static JPanel ImagePanel(JComponent c, String imgURL, int imgWidth, int imgHeight, int x, int y) {
        imgPanel = new ImagePanel(imgURL, imgWidth, imgHeight, x, y);
        return imgPanel;
    }
    /**
     * 图片背景面板,加载背景图片等情况使用
     * @param f 父窗口
     * @param imgURL 图片的存放路径
     * @param imgWidth 设置图片宽度
     * @param imgHeight 设置图片高度
     * @param x 设置图片水平位置
     * @param y 设置图片垂直位置
     */
    public static JPanel ImagePanel(JFrame f, String imgURL, int imgWidth, int imgHeight, int x, int y) {
        imgPanel = new ImagePanel(imgURL, imgWidth, imgHeight, x, y);
        return imgPanel;
    }
    /**
     * 背景颜色为 color 的按钮
     * @param c 父组件
     * @param label 按钮文本
     * @param color 按钮背景颜色
     * @param btnWidth 按钮宽度,多数情况下可设为 90
     * @param btnHeight 按钮高度,多数情况下可设为 30
     * @param x 按钮的水平位置
     * @param y 按钮的垂直位置
     */
    public static JButton ColorButton(JComponent c, String label, int fontSize, Color color, int btnWidth, int btnHeight, int x, int y) {
        colorBtn = new JButton(label);
        colorBtn.setFont(new Font("", Font.BOLD, fontSize));
        colorBtn.setBackground(color);
        colorBtn.setForeground(Color.WHITE);
        colorBtn.setBorder(null);
        colorBtn.setPreferredSize(new Dimension(90, 30));
        colorBtn.setBounds(x, y, btnWidth, btnHeight);
        return colorBtn;
    }
    /**
     * 背景颜色为 color 的按钮
     * @param c 父组件
     * @param label 按钮文本
     * @param color 按钮背景颜色
     * @param btnWidth 按钮宽度,多数情况下可设为 90
     * @param btnHeight 按钮高度,多数情况下可设为 30
     */
    public static JButton ColorButton(JComponent c, String label, int fontSize, Color color, int btnWidth, int btnHeight) {
        colorBtn = new JButton(label);
        colorBtn.setFont(new Font("", Font.BOLD, fontSize));
        colorBtn.setBackground(color);
        colorBtn.setForeground(Color.WHITE);
        colorBtn.setBorder(null);
        colorBtn.setPreferredSize(new Dimension(90, 30));
        return colorBtn;
    }
    /**
     * 带样式的提示文本信息,具有前景色(文本颜色)和背景色属性,位置,宽高等
     * @param c 父组件
     * @param label 文本信息
     * @param fontSize 文本字体大小
     * @param bgColor 文本背景色
     * @param fgColor 文本前景色(文本颜色)
     * @param width 文本组件宽度
     * @param height 文本组件高度
     * @param x 文本的水平位置
     * @param y 文本的垂直位置
     */
    public static JLabel NoticeLabel(JComponent c, String label, int fontSize, Color bgColor, Color fgColor, int width, int height, int x, int y) {
        nLabel = new JLabel(label);
        nLabel.setFont(new Font("", Font.BOLD, fontSize));
        nLabel.setBackground(bgColor);
        nLabel.setForeground(fgColor);
        nLabel.setBounds(x, y, width, height);
        return nLabel;
    }
    /**
     * 带样式的提示文本信息,具有前景色(文本颜色)和背景色属性等
     * @param c 父组件
     * @param label 文本信息
     * @param fontSize 文本字体大小
     * @param bgColor 文本背景色
     * @param fgColor 文本前景色(文本颜色)
     */
    public static JLabel NoticeLabel(JComponent c, String label, int fontSize, Color bgColor, Color fgColor) {
        nLabel = new JLabel(label);
        nLabel.setFont(new Font("", Font.BOLD, fontSize));
        nLabel.setBackground(bgColor);
        nLabel.setForeground(fgColor);
        return nLabel;
    }
    public static JTextArea MTextArea(String text,String fontName, int fontStyle, int fontSize, Color bgColor, Color fgColor, int width, int height, int x, int y) {
        tArea = new JTextArea(text);
        tArea.setFont(new Font(fontName, fontStyle, fontSize));
        tArea.setEditable(false);
        tArea.setBackground(bgColor);
        tArea.setForeground(fgColor);
        tArea.setLineWrap(true);
        tArea.setBounds(x, y, width, height);
        tArea.setBorder(null);
        return tArea;
    }
}
class LocationCtrl {
    private static Toolkit toolkit = Toolkit.getDefaultToolkit();                                   // 系统工具包
    private static final int SCREEN_WIDTH = toolkit.getScreenSize().width;              // 获取当前主屏幕宽度
    private static final int SCREEN_HEIGHT = toolkit.getScreenSize().height;                // 获取当前主屏幕高度
    private static final double scale = SCREEN_WIDTH/SCREEN_HEIGHT;                 // 屏幕宽高比

    private static int FRAME_WIDTH;                                     // 主窗口宽度
    private static int FRAME_HEIGHT;                                        // 主窗口高度

    private static int MAIN_XL = (SCREEN_WIDTH - SCREEN_HEIGHT*8/5)/2;                  // 主窗口水平位置(宽屏,下同)
    private static int MAIN_YL = SCREEN_HEIGHT /20;                                                     // 主窗口垂直位置
    private static int OTHER_XL  = (SCREEN_WIDTH - SCREEN_HEIGHT*4/5)/2;                    // 其他窗口水平位置
    private static int OTHER_YL = SCREEN_HEIGHT *11/40;                                             // 其他窗口垂直位置
    private static int DIALOG_XL = (SCREEN_WIDTH - SCREEN_HEIGHT*8/15)/2;               // 提示窗口水平位置
    private static int DIALOG_YL = SCREEN_HEIGHT * 7/20;                                                // 提示窗口垂直位置

    private static int MAIN_XS = SCREEN_WIDTH /20;                                                      // 主窗口水平位置(窄屏,下同)
    private static int MAIN_YS= (SCREEN_HEIGHT - SCREEN_WIDTH * 81/160) /2;             // 主窗口垂直位置
    private static int OTHER_XS  = SCREEN_WIDTH * 11/40;                                                // 其他窗口水平位置
    private static int OTHER_YS = (SCREEN_HEIGHT - SCREEN_WIDTH * 81/320)/2;                                        // 其他窗口垂直位置
    private static int DIALOG_XS = SCREEN_WIDTH * 7/20;                                             // 提示窗口水平位置
    private static int DIALOG_YS = (SCREEN_HEIGHT - SCREEN_WIDTH * 27/160)/2;           // 提示窗口垂直位置

    /**
     * 主界面窗口尺寸控制
     * 如果当前屏幕尺寸宽高比大于 16/9,设置窗口位置为屏幕高的 8/5 和 9/10
     * 如果小于等于 16/9,设置窗口位置为屏幕宽的 9/10 和 81/160
     */
    public static Point mainFrameLocationCtrl() {
        if (scale > 16/9) {
            return new Point(MAIN_XL, MAIN_YL);
        } else {
            return new Point(MAIN_XS, MAIN_YS);
        }
    }
    /**
     * 提示窗口尺寸控制
     * 如果当前屏幕尺寸宽高比大于 16/9,设置窗口位置为屏幕高的 8/15 和 3/10
     * 如果小于等于 16/9,设置窗口位置为屏幕宽的 3/10 和 27/160
     */
    public static Point dialogLocationCtrl() {
        if (scale > 16/9) {
            return new Point(DIALOG_XL, DIALOG_YL);
        } else {
            return new Point(DIALOG_XS, DIALOG_YS);
        }
    }
    /**
     * 其他界面窗口尺寸控制
     * 如果当前屏幕尺寸宽高比大于 16/9,设置窗口位置为屏幕高的 4/5 和 9/20
     * 如果小于等于 16/9,设置窗口位置为屏幕宽的 9/20 和 81/320
     */
    public static Point otherFrameLocationCtrl() {
        if (scale > 16/9) {
            return new Point(OTHER_XL, OTHER_YL);
        } else {
            return new Point(OTHER_XS, OTHER_YS);
        }
    }
}
class SizeCtrl {
    private static Toolkit toolkit = Toolkit.getDefaultToolkit();                                   // 系统工具包
    private static final int SCREEN_WIDTH = toolkit.getScreenSize().width;              // 获取当前主屏幕宽度
    private static final int SCREEN_HEIGHT = toolkit.getScreenSize().height;                // 获取当前主屏幕高度
    private static final double scale = SCREEN_WIDTH/SCREEN_HEIGHT;                 // 屏幕宽高比

    private static int FRAME_WIDTH;                                 // 主窗口宽度
    private static int FRAME_HEIGHT;                                    // 主窗口高度

    /**
     * 主界面窗口尺寸控制
     * 如果当前屏幕尺寸宽高比大于 16/9,设置窗口宽高尺寸为屏幕高的 8/5 和 9/10
     * 如果小于等于 16/9,设置窗口宽高尺寸为屏幕宽的 9/10 和 81/160
     */
    public static Dimension mainFrameSizeCtrl() {
        if (scale > 16/9) {
            FRAME_WIDTH = SCREEN_HEIGHT * 8/5;
            FRAME_HEIGHT = SCREEN_HEIGHT * 9/10;
        } else {
            FRAME_WIDTH = SCREEN_WIDTH * 9/10;
            FRAME_HEIGHT = SCREEN_WIDTH * 81/160;
        }
        return new Dimension(FRAME_WIDTH, FRAME_HEIGHT);
    }
    /**
     * 提示窗口尺寸控制
     * 如果当前屏幕尺寸宽高比大于 16/9,设置窗口宽高尺寸为屏幕高的 8/15 和 3/10
     * 如果小于等于 16/9,设置窗口宽高尺寸为屏幕宽的 3/10 和 27/160
     */
    public static Dimension dialogSizeCtrl() {
        if (scale > 16/9) {
            FRAME_WIDTH = SCREEN_HEIGHT * 8/15;
            FRAME_HEIGHT = SCREEN_HEIGHT * 3/10;
        } else {
            FRAME_WIDTH = SCREEN_WIDTH * 3/10;
            FRAME_HEIGHT = SCREEN_WIDTH * 27/160;
        }
        return new Dimension(FRAME_WIDTH, FRAME_HEIGHT);
    }
    /**
     * 其他界面窗口尺寸控制
     * 如果当前屏幕尺寸宽高比大于 16/9,设置窗口宽高尺寸为屏幕高的 4/5 和 9/20
     * 如果小于等于 16/9,设置窗口宽高尺寸为屏幕宽的 9/20 和 81/320
     */
    public static Dimension otherFrameSizeCtrl() {
        if (scale > 16/9) {
            FRAME_WIDTH = SCREEN_HEIGHT * 4/5;
            FRAME_HEIGHT = SCREEN_HEIGHT * 9/20;
        } else {
            FRAME_WIDTH = SCREEN_WIDTH * 9/20;
            FRAME_HEIGHT = SCREEN_WIDTH * 81/320;
        }
        return new Dimension(FRAME_WIDTH, FRAME_HEIGHT);
    }
}
class MenuUI extends BasicMenuUI {
    public MenuUI(Color bgColor, Color fgColor) {
        super.selectionBackground = bgColor;
        super.selectionForeground = fgColor;
    }
}
class MenuItemUI extends BasicMenuItemUI {
    public MenuItemUI(Color bgColor, Color fgColor) {
        super.selectionBackground = bgColor;
        super.selectionForeground = fgColor;
    }
}
class MenuItemExitedUI extends BasicMenuItemUI {
    public MenuItemExitedUI() {
        super.selectionBackground = new Color(0, 0, 0, 0.25f);
        super.selectionForeground = Color.WHITE;
    }
}

And I set all of these item's background to new Color(0,0,0,0.25f). Them I got this result:

我将所有这些项的背景设置为new Color(0,0,0,0,0.25f)。我得到了这个结果:

使用JMenuBar、JMenu和JMenuItem自设计菜单栏时,会出现奇怪的呈现。

I am surprised to find that there exists a white background below my JMenuItem as the red arrow show. And the item has a right new Color(0,0,0,0.25f) background as the black arrow show. By the way, I had set my main panel's background to a picture as the orange arrow show.

我惊讶地发现,在我的JMenuItem下面存在一个白色背景,就像红色箭头所显示的那样。并且该项目有一个正确的新颜色(0,0,0,0.25f)背景为黑色箭头显示。顺便说一下,我把主面板的背景设置为橙色箭头显示。

Anyone can answer me where is this strage white background comes from? And how can I remove it or make it to invisible?

谁能回答我这个白色的背景是从哪里来的?我该如何移除它或使之隐形?

1 个解决方案

#1


1  

使用JMenuBar、JMenu和JMenuItem自设计菜单栏时,会出现奇怪的呈现。

  • It is tested on MetalLookAndFeel only.
  • 它只在金属表面上进行测试。
import java.awt.*;
import java.awt.image.*;
import java.util.Objects;
import javax.swing.*;
import javax.swing.plaf.*;

public class MenuBarRootPaneTest {
  private static final Color ALPHA_ZERO = new Color(0x0, true);
  private static final Color POPUP_BACK = new Color(0, 0, 0, .25f);

  private static JMenuBar createMenuBar() {
    JMenuBar mb = new JMenuBar() {
      @Override public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d.height = 36;
        return d;
      }
      @Override public boolean isOpaque() {
        return false;
      }
      @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setPaint(POPUP_BACK);
        g2.fillRect(0, 0, getWidth(), getHeight());
        g2.dispose();
      }
    };
    String[] menuKeys = {"File", "Edit", "Help"};
    for (String key : menuKeys) {
      mb.add(createMenu(key));
    }
    return mb;
  }

  private static JMenu createMenu(String key) {
    JMenu menu = new TransparentMenu(key);
    menu.add(new JMenuItem("JMenuItem 1"));
    menu.add(new JMenuItem("JMenuItem 2"));
    menu.add(new JMenuItem("JMenuItem 3"));
    return menu;
  }

  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      //UIManager.put("MenuBar.background", POPUP_BACK);
      UIManager.put("MenuBar.border",     BorderFactory.createEmptyBorder());
      UIManager.put("PopupMenu.border",   BorderFactory.createEmptyBorder());

      UIManager.put("Menu.foreground",              Color.WHITE);
      UIManager.put("Menu.background",              ALPHA_ZERO);
      UIManager.put("Menu.selectionBackground",     POPUP_BACK);
      UIManager.put("Menu.selectionForeground",     Color.WHITE);
      UIManager.put("Menu.borderPainted",           Boolean.FALSE);

      UIManager.put("MenuItem.foreground",          Color.WHITE);
      UIManager.put("MenuItem.background",          ALPHA_ZERO);
      UIManager.put("MenuItem.selectionBackground", POPUP_BACK);
      UIManager.put("MenuItem.selectionForeground", Color.WHITE);
      UIManager.put("MenuItem.borderPainted",       Boolean.FALSE);

      JFrame frame = new JFrame() {
        @Override protected JRootPane createRootPane() {
          return new JRootPane() {
            //private final Image img = new ImageIcon("img.png").getImage();
            private final TexturePaint texture = makeTexturePaint();
            @Override protected void paintComponent(Graphics g) {
              super.paintComponent(g);
              Graphics2D g2 = (Graphics2D) g.create();
              g2.setPaint(texture);
              g2.fillRect(0, 0, getWidth(), getHeight());
              //g2.drawImage(img, 0, 0, img.getWidth(this), img.getHeight(this), this);
              g2.dispose();
            }
            @Override public boolean isOpaque() {
              return true;
            }
          };
        }
      };
      frame.getRootPane().setBackground(Color.BLUE);
      ((JComponent) frame.getContentPane()).setOpaque(false);
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      frame.setJMenuBar(createMenuBar());
      frame.setSize(320, 240);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    });
  }

  // TranslucentPopupMenu
  // http://ateraimemo.com/Swing/TranslucentPopupMenu.html
  static class TranslucentPopupMenu extends JPopupMenu {
    @Override public boolean isOpaque() {
      return false;
    }
    @Override public void show(Component c, int x, int y) {
      EventQueue.invokeLater(() -> {
        Container p = getTopLevelAncestor();
        if (p instanceof JWindow) {
          System.out.println("Heavy weight");
          ((JWindow) p).setBackground(ALPHA_ZERO);
        }
      });
      super.show(c, x, y);
    }
    @Override protected void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setPaint(POPUP_BACK);
      g2.fillRect(0, 0, getWidth(), getHeight());
      g2.dispose();
    }
  }

  static class TransparentMenu extends JMenu {
    private JPopupMenu popupMenu;

    protected TransparentMenu(String title) {
      super(title);
    }
    @Override public boolean isOpaque() {
      return false;
    }
    // Bug ID: JDK-4688783 JPopupMenu hardcoded i JMenu
    // http://bugs.java.com/view_bug.do?bug_id=4688783
    private void ensurePopupMenuCreated() {
      if (Objects.isNull(popupMenu)) {
        this.popupMenu = new TranslucentPopupMenu();
        popupMenu.setInvoker(this);
        popupListener = createWinListener(popupMenu);
      }
    }
    @Override public JPopupMenu getPopupMenu() {
      ensurePopupMenuCreated();
      return popupMenu;
    }
    @Override public JMenuItem add(JMenuItem menuItem) {
      ensurePopupMenuCreated();
      menuItem.setOpaque(false);
      return popupMenu.add(menuItem);
    }
    @Override public Component add(Component c) {
      ensurePopupMenuCreated();
      if (c instanceof JComponent) {
        ((JComponent) c).setOpaque(false);
      }
      popupMenu.add(c);
      return c;
    }
    @Override public void addSeparator() {
      ensurePopupMenuCreated();
      popupMenu.addSeparator();
    }
    @Override public void insert(String s, int pos) {
      if (pos < 0) {
        throw new IllegalArgumentException("index less than zero.");
      }
      ensurePopupMenuCreated();
      popupMenu.insert(new JMenuItem(s), pos);
    }
    @Override public JMenuItem insert(JMenuItem mi, int pos) {
      if (pos < 0) {
        throw new IllegalArgumentException("index less than zero.");
      }
      ensurePopupMenuCreated();
      popupMenu.insert(mi, pos);
      return mi;
    }
    @Override public void insertSeparator(int index) {
      if (index < 0) {
        throw new IllegalArgumentException("index less than zero.");
      }
      ensurePopupMenuCreated();
      popupMenu.insert(new JPopupMenu.Separator(), index);
    }
    @Override public boolean isPopupMenuVisible() {
      ensurePopupMenuCreated();
      return popupMenu.isVisible();
    }
  }

  private static TexturePaint makeTexturePaint() {
    int cs = 6;
    int sz = cs * cs;
    BufferedImage img = new BufferedImage(sz, sz, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = img.createGraphics();
    g2.setPaint(new Color(200, 200, 200, 50));
    g2.fillRect(0, 0, sz, sz);
    for (int i = 0; i * cs < sz; i++) {
      for (int j = 0; j * cs < sz; j++) {
        if ((i + j) % 2 == 0) {
          g2.fillRect(i * cs, j * cs, cs, cs);
        }
      }
    }
    g2.dispose();
    return new TexturePaint(img, new Rectangle(sz, sz));
  }
}

#1


1  

使用JMenuBar、JMenu和JMenuItem自设计菜单栏时,会出现奇怪的呈现。

  • It is tested on MetalLookAndFeel only.
  • 它只在金属表面上进行测试。
import java.awt.*;
import java.awt.image.*;
import java.util.Objects;
import javax.swing.*;
import javax.swing.plaf.*;

public class MenuBarRootPaneTest {
  private static final Color ALPHA_ZERO = new Color(0x0, true);
  private static final Color POPUP_BACK = new Color(0, 0, 0, .25f);

  private static JMenuBar createMenuBar() {
    JMenuBar mb = new JMenuBar() {
      @Override public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d.height = 36;
        return d;
      }
      @Override public boolean isOpaque() {
        return false;
      }
      @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setPaint(POPUP_BACK);
        g2.fillRect(0, 0, getWidth(), getHeight());
        g2.dispose();
      }
    };
    String[] menuKeys = {"File", "Edit", "Help"};
    for (String key : menuKeys) {
      mb.add(createMenu(key));
    }
    return mb;
  }

  private static JMenu createMenu(String key) {
    JMenu menu = new TransparentMenu(key);
    menu.add(new JMenuItem("JMenuItem 1"));
    menu.add(new JMenuItem("JMenuItem 2"));
    menu.add(new JMenuItem("JMenuItem 3"));
    return menu;
  }

  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      //UIManager.put("MenuBar.background", POPUP_BACK);
      UIManager.put("MenuBar.border",     BorderFactory.createEmptyBorder());
      UIManager.put("PopupMenu.border",   BorderFactory.createEmptyBorder());

      UIManager.put("Menu.foreground",              Color.WHITE);
      UIManager.put("Menu.background",              ALPHA_ZERO);
      UIManager.put("Menu.selectionBackground",     POPUP_BACK);
      UIManager.put("Menu.selectionForeground",     Color.WHITE);
      UIManager.put("Menu.borderPainted",           Boolean.FALSE);

      UIManager.put("MenuItem.foreground",          Color.WHITE);
      UIManager.put("MenuItem.background",          ALPHA_ZERO);
      UIManager.put("MenuItem.selectionBackground", POPUP_BACK);
      UIManager.put("MenuItem.selectionForeground", Color.WHITE);
      UIManager.put("MenuItem.borderPainted",       Boolean.FALSE);

      JFrame frame = new JFrame() {
        @Override protected JRootPane createRootPane() {
          return new JRootPane() {
            //private final Image img = new ImageIcon("img.png").getImage();
            private final TexturePaint texture = makeTexturePaint();
            @Override protected void paintComponent(Graphics g) {
              super.paintComponent(g);
              Graphics2D g2 = (Graphics2D) g.create();
              g2.setPaint(texture);
              g2.fillRect(0, 0, getWidth(), getHeight());
              //g2.drawImage(img, 0, 0, img.getWidth(this), img.getHeight(this), this);
              g2.dispose();
            }
            @Override public boolean isOpaque() {
              return true;
            }
          };
        }
      };
      frame.getRootPane().setBackground(Color.BLUE);
      ((JComponent) frame.getContentPane()).setOpaque(false);
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      frame.setJMenuBar(createMenuBar());
      frame.setSize(320, 240);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    });
  }

  // TranslucentPopupMenu
  // http://ateraimemo.com/Swing/TranslucentPopupMenu.html
  static class TranslucentPopupMenu extends JPopupMenu {
    @Override public boolean isOpaque() {
      return false;
    }
    @Override public void show(Component c, int x, int y) {
      EventQueue.invokeLater(() -> {
        Container p = getTopLevelAncestor();
        if (p instanceof JWindow) {
          System.out.println("Heavy weight");
          ((JWindow) p).setBackground(ALPHA_ZERO);
        }
      });
      super.show(c, x, y);
    }
    @Override protected void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setPaint(POPUP_BACK);
      g2.fillRect(0, 0, getWidth(), getHeight());
      g2.dispose();
    }
  }

  static class TransparentMenu extends JMenu {
    private JPopupMenu popupMenu;

    protected TransparentMenu(String title) {
      super(title);
    }
    @Override public boolean isOpaque() {
      return false;
    }
    // Bug ID: JDK-4688783 JPopupMenu hardcoded i JMenu
    // http://bugs.java.com/view_bug.do?bug_id=4688783
    private void ensurePopupMenuCreated() {
      if (Objects.isNull(popupMenu)) {
        this.popupMenu = new TranslucentPopupMenu();
        popupMenu.setInvoker(this);
        popupListener = createWinListener(popupMenu);
      }
    }
    @Override public JPopupMenu getPopupMenu() {
      ensurePopupMenuCreated();
      return popupMenu;
    }
    @Override public JMenuItem add(JMenuItem menuItem) {
      ensurePopupMenuCreated();
      menuItem.setOpaque(false);
      return popupMenu.add(menuItem);
    }
    @Override public Component add(Component c) {
      ensurePopupMenuCreated();
      if (c instanceof JComponent) {
        ((JComponent) c).setOpaque(false);
      }
      popupMenu.add(c);
      return c;
    }
    @Override public void addSeparator() {
      ensurePopupMenuCreated();
      popupMenu.addSeparator();
    }
    @Override public void insert(String s, int pos) {
      if (pos < 0) {
        throw new IllegalArgumentException("index less than zero.");
      }
      ensurePopupMenuCreated();
      popupMenu.insert(new JMenuItem(s), pos);
    }
    @Override public JMenuItem insert(JMenuItem mi, int pos) {
      if (pos < 0) {
        throw new IllegalArgumentException("index less than zero.");
      }
      ensurePopupMenuCreated();
      popupMenu.insert(mi, pos);
      return mi;
    }
    @Override public void insertSeparator(int index) {
      if (index < 0) {
        throw new IllegalArgumentException("index less than zero.");
      }
      ensurePopupMenuCreated();
      popupMenu.insert(new JPopupMenu.Separator(), index);
    }
    @Override public boolean isPopupMenuVisible() {
      ensurePopupMenuCreated();
      return popupMenu.isVisible();
    }
  }

  private static TexturePaint makeTexturePaint() {
    int cs = 6;
    int sz = cs * cs;
    BufferedImage img = new BufferedImage(sz, sz, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = img.createGraphics();
    g2.setPaint(new Color(200, 200, 200, 50));
    g2.fillRect(0, 0, sz, sz);
    for (int i = 0; i * cs < sz; i++) {
      for (int j = 0; j * cs < sz; j++) {
        if ((i + j) % 2 == 0) {
          g2.fillRect(i * cs, j * cs, cs, cs);
        }
      }
    }
    g2.dispose();
    return new TexturePaint(img, new Rectangle(sz, sz));
  }
}