5

我想自定义外观,JPopupMenu所以我创建了一个自定义类来扩展 JPopupMenu 类,因为我覆盖了该paintComponent方法,就像我对需要自定义的任何组件所做的那样。

public class CustomPopupMenu extends JPopupMenu {

    @Override
    public paintComponent(Graphics g) {
        //custom draw
    }
}

我唯一知道的问题是我无法使JPopupMenu透明。我虽然setOpaque(false)就够了,但我错了。

我怎样才能使JPopupMenu透明?

4

4 回答 4

4

jpopupmenu 是一个窗口吗?

是的JPopup是容器,例如

在此处输入图像描述

Java6 的代码(必须更改 Java7 的导入)

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;

public class TranslucentWindow extends JFrame {

    private static final long serialVersionUID = 1L;
    private JMenuItem m_mniInsertRow;
    private JMenuItem m_mniInsertScrip;
    private JMenuItem m_mniDeleterRow;
    private JMenuItem m_mniDeleteExpiredScrip;
    private JMenuItem m_mniSetAlert;

    public TranslucentWindow() {
        super("Test translucent window");
        setLayout(new FlowLayout());
        add(new JButton("test"));
        add(new JCheckBox("test"));
        add(new JRadioButton("test"));
        add(new JProgressBar(0, 100));
        JPanel panel = new JPanel() {

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 300);
            }
            private static final long serialVersionUID = 1L;

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.red);
                g.fillRect(0, 0, getWidth(), getHeight());
            }
        };
        panel.add(new JLabel("Very long textxxxxxxxxxxxxxxxxxxxxx "));
        add(panel);
        final JPopupMenu popupMenu = new JPopupMenu();
        m_mniInsertRow = new JMenuItem("Insert a Row");
        m_mniInsertRow.setOpaque(false);
        m_mniInsertScrip = new JMenuItem("Insert a Scrip");
        m_mniInsertScrip.setOpaque(false);
        m_mniDeleterRow = new JMenuItem("Delete a Row");
        m_mniDeleterRow.setOpaque(false);
        m_mniDeleteExpiredScrip = new JMenuItem("Delete a Expired Scrip");
        m_mniDeleteExpiredScrip.setOpaque(false);
        m_mniSetAlert = new JMenuItem("Set Alert");
        m_mniSetAlert.setOpaque(false);
        popupMenu.add(m_mniInsertRow);
        popupMenu.add(m_mniInsertScrip);
        popupMenu.addSeparator();
        popupMenu.add(m_mniDeleterRow);
        popupMenu.add(m_mniDeleteExpiredScrip);
        popupMenu.add(new JSeparator());
        popupMenu.add(m_mniSetAlert);
        panel.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    int x = e.getX();
                    int y = e.getY();
                    popupMenu.show(e.getComponent(), x, y);
                }
            }
        });
        setSize(new Dimension(400, 300));
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        JFrame.setDefaultLookAndFeelDecorated(true);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                Window w = new TranslucentWindow();
                w.setVisible(true);
                com.sun.awt.AWTUtilities.setWindowOpacity(w, 0.7f);
            }
        });
    }
}

编辑

Translucency对和的有趣支持Nimbus L&F,尤其是Painter再现非常正确Color的(梯度也在屏幕上移动),对 JPopupMenu 进行了重要更改的 ligth 版本,仍然来自 Java6

图片

在此处输入图像描述

从代码

import com.sun.java.swing.Painter;
import java.awt.*;
import javax.swing.*;

public class TranslucentWindow extends JFrame {

    private static final long serialVersionUID = 1L;
    private JPopupMenu popupMenu = new JPopupMenu();
    private JMenuItem m_mniInsertRow = new JMenuItem("Insert a Row");
    private JMenuItem m_mniInsertScrip = new JMenuItem("Delete a Row");
    private JMenuItem m_mniDeleterRow = new JMenuItem("Insert a Scrip");
    private JMenuItem m_mniDeleteExpiredScrip = new JMenuItem("Delete a Expired Scrip");
    private JMenuItem m_mniSetAlert = new JMenuItem("Set Alert");

    public TranslucentWindow() {
        super("Test translucent window");
        setLayout(new FlowLayout());
        add(new JButton("test"));
        add(new JCheckBox("test"));
        add(new JRadioButton("test"));
        add(new JProgressBar(0, 100));
        JPanel panel = new JPanel() {

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 300);
            }
            private static final long serialVersionUID = 1L;

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.red);
                g.fillRect(0, 0, getWidth(), getHeight());
            }
        };
        panel.add(new JLabel("Very long textxxxxxxxxxxxxxxxxxxxxx "));
        panel.setComponentPopupMenu(popupMenu);
        add(panel);
        m_mniInsertRow.setOpaque(false);
        m_mniInsertScrip.setOpaque(false);
        m_mniDeleterRow.setOpaque(false);
        m_mniDeleteExpiredScrip.setOpaque(false);
        m_mniSetAlert.setOpaque(false);
        popupMenu.add(m_mniInsertRow);
        popupMenu.add(m_mniInsertScrip);
        popupMenu.addSeparator();
        popupMenu.add(m_mniDeleterRow);
        popupMenu.add(m_mniDeleteExpiredScrip);
        popupMenu.add(new JSeparator());
        popupMenu.add(m_mniSetAlert);
        setSize(new Dimension(400, 300));
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        try {
            for (UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    UIManager.getLookAndFeelDefaults().put("nimbusOrange", (new Color(127, 255, 191)));
                    UIManager.getLookAndFeelDefaults().put("PopupMenu[Enabled].backgroundPainter",
                            new FillPainter(new Color(127, 255, 191)));

                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
        } catch (InstantiationException ex) {
        } catch (IllegalAccessException ex) {
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        }
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                Window w = new TranslucentWindow();
                w.setVisible(true);
                com.sun.awt.AWTUtilities.setWindowOpacity(w, 0.7f);
            }
        });
    }

    static class FillPainter implements Painter<JComponent> {

        private final Color color;

        FillPainter(Color c) {
            color = c;
        }

        @Override
        public void paint(Graphics2D g, JComponent object, int width, int height) {
            g.setColor(color);
            g.fillRect(0, 0, width - 1, height - 1);
        }
    }
}
于 2012-10-09T13:57:53.907 回答
3

弹出菜单的问题在于它可能实现为顶层容器(Window),而一个窗口是不透明的,无论你用setOpaque()设置什么值,它都是不透明的。但是窗户也可以做成半透明的。

您可以通过强制使用重量级弹出窗口并粗暴地改变其不透明度来破解它。试试这个作为实验的起点(Java7):

import java.awt.Window;

import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

public class TranslucentPopup extends JPopupMenu {

    {
        // need to disable that to work
        setLightWeightPopupEnabled(false);
    }

    @Override
    public void setVisible(boolean visible) {
        if (visible == isVisible())
            return;
        super.setVisible(visible);
        if (visible) {
            // attempt to set tranparency
            try {
                Window w = SwingUtilities.getWindowAncestor(this);
                w.setOpacity(0.667F);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

请注意,它不会使子菜单半透明!

于 2012-10-09T14:17:37.687 回答
2

您不必扩展JPopupMenu类,只需使您的菜单不透明,然后JMenuItems改为透明(并且不透明)。

public class CustomMenuItem extends JMenuItem {
        public void paint(Graphics g) { 
                Graphics2D g2d = (Graphics2D) g.create(); 
                g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f)); 
                super.paint(g2d); 
                g2d.dispose(); 
        } 
}

在此处输入图像描述

或者,做相反的事情,扩展JPopupMenu以使其透明并保持菜单和项目不透明(这样就不会像上面那样菜单的不透明边框)。

编辑:

请注意(不幸的是)当弹出菜单超出框架边界时它不起作用,正如@Durandal所说。

尽管您可以尝试进行一些计算并更改弹出窗口的位置(在需要时)以使其始终保持在框架内。

于 2012-10-09T14:13:33.417 回答
1

请参阅 Kirill Grouchnikov 撰写的这篇出色的 2008 年文章Translucent and Shaped Swing Windows

根据上述文章中给出的示例和从 JGoodies 项目中借用的代码,您可以使用以下 2 个类安装自定义弹出窗口外观:

  1. TranslucentPopup 是自定义的 Popup,由 JPopupMenu 使用:

    /**
     * Translucent Popup
     *
     * @author Kirill Grouchnikov [https://www.java.net/pub/au/275]
     */
    public class TranslucentPopup extends Popup {
        final JWindow popupWindow;
    
        TranslucentPopup(Component contents, int ownerX, int ownerY) {
            // create a new heavyweight window
            popupWindow = new JWindow();
            // mark the popup with partial opacity
            com.sun.awt.AWTUtilities.setWindowOpacity(popupWindow, 0.7f);
            // determine the popup location
            popupWindow.setLocation(ownerX, ownerY);
            // add the contents to the popup
            popupWindow.getContentPane().add(contents, BorderLayout.CENTER);
            contents.invalidate();
            JComponent parent = (JComponent) contents.getParent();
            // set a custom border
            parent.setBorder(BorderFactory.createRaisedSoftBevelBorder());
        }
    
        public void show() {
            popupWindow.setVisible(true);
            popupWindow.pack();
            // mark the window as non-opaque, so that the
            // border pixels take on the per-pixel opacity
            com.sun.awt.AWTUtilities.setWindowOpaque(popupWindow, false);
        }
    
        public void hide() {
            popupWindow.setVisible(false);
        }
    }
    
  2. TranslucentPopupFactory 需要安装自定义外观:

    /**
     * Translucent Popup Factory
     *
     * @author Kirill Grouchnikov [https://www.java.net/pub/au/275]
     * @author Karsten Lentzsch (JGoodies project)
     */
    public class TranslucentPopupFactory extends PopupFactory {
        /**
         * The PopupFactory used before this PopupFactory has been installed in
         * {@code #install}. Used to restored the original state in
         * {@code #uninstall}.
         */
        protected final PopupFactory storedFactory;
    
        protected TranslucentPopupFactory(PopupFactory originalFactory) {
            storedFactory = originalFactory;
        }
    
        public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException {
            // A more complete implementation would cache and reuse popups
            return new TranslucentPopup(contents, x, y);
        }
    
        /**
          * Utility method to install the custom Popup Look and feel.
          * Call this method once during your application start-up.
          *
          * @author Karsten Lentzsch (JGoodies project)
          */
        public static void install() {
            PopupFactory factory = PopupFactory.getSharedInstance();
            if (factory instanceof TranslucentPopupFactory) {
                return;
            }
    
            PopupFactory.setSharedInstance(new TranslucentPopupFactory(factory));
        }
    
        /**
          * Utility method to uninstall the custom Popup Look and feel
          * @author Karsten Lentzsch (JGoodies project)
          */
        public static void uninstall() {
            PopupFactory factory = PopupFactory.getSharedInstance();
            if (!(factory instanceof TranslucentPopupFactory)) {
                return;
            }
    
            PopupFactory stored = ((TranslucentPopupFactory) factory).storedFactory;
            PopupFactory.setSharedInstance(stored);
        }
    }
    

结果是所有弹出窗口(包括 JPopupMenu 和可能还有 ToolTips)现在都将是半透明的,并且可以选择具有自定义边框: World Wind Context Menu 示例应用程序中显示的半透明上下文菜单

于 2013-10-04T02:08:15.050 回答