如何让JPopupMenu透明化?

时间:2012-10-09 13:21:58

标签: java swing transparent jpopupmenu jpopup

我想自定义JPopupMenu的外观,所以我在i上创建了一个扩展JPopupMenu类的自定义类覆盖paintComponent方法,就像我需要自定义的任何组件一样。< / p>

public class CustomPopupMenu extends JPopupMenu {

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

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

如何让JPopupMenu透明?

4 个答案:

答案 0 :(得分:4)

  

jpopupmenu是一个窗口?

JPopup是容器,例如

enter image description here

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

修改

TranslucencyNimbus L&F的有趣支持,特别是Painter再现非常正确Color(Gradiend也在屏幕上移动),带有JPopupMenu重要更改的版本,仍然来自Java6

图像

enter image description here

来自代码

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

答案 1 :(得分: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(); 
        } 
}

enter image description here

或者,相反,延伸JPopupMenu使其透明,并保持菜单和项目不透明(这样就不会有像上面那样的菜单的不透明边框)。

编辑:

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

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

答案 2 :(得分:2)

弹出菜单的问题在于它可能被实现为顶级容器(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();
            }
        }
    }

}

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

答案 3 :(得分:1)

请参阅Kirill Grouchnikov撰写的2008年优秀文章Translucent and Shaped Swing Windows

根据上面文章中给出的示例和从JGoodies项目借来的代码,您可以安装自定义弹出窗口Look&amp;感觉使用以下两个类:

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

    /**
     * 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);
        }
    }
    
  3. 结果是所有弹出窗口(包括JPopupMenu,也许还有工具提示)现在都是半透明的,并且可选地具有自定义边框: Translucent Context Menu shown on World Wind Context Menu example app