简体   繁体   English

如何让JPopupMenu透明化?

[英]How can i make a JPopupMenu transparent?

I'd like to customize the look of JPopupMenu so i made a custom class extending the JPopupMenu class on i overrode the paintComponent method as i would do for any component i need to customize. 我想自定义JPopupMenu的外观,所以我在i上创建了一个扩展JPopupMenu类的自定义类覆盖了paintComponent方法,就像我需要自定义的任何组件一样。

public class CustomPopupMenu extends JPopupMenu {

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

The only problem i have right know is that i'm not able to make the JPopupMenu transparent. 我知道的唯一问题是我无法使JPopupMenu透明化。 I though setOpaque(false) would be enough, i was wrong. 我虽然setOpaque(false)就够了,我错了。

How can i make a JPopupMenu transparent? 如何让JPopupMenu透明化?

jpopupmenu is a window? jpopupmenu是一个窗口?

yes JPopup is container, for example 是的,例如, JPopup是容器

在此输入图像描述

code for Java6 (have to change imports for Java7) 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);
            }
        });
    }
}

EDIT 编辑

interesting support for Translucency and Nimbus L&F , especially Painter reproducing quite correct Color (Gradiend too on movement over the screen), ligth version with important changes for JPopupMenu, still from Java6 TranslucencyNimbus L&F有趣支持,特别是Painter再现非常正确的Color (Gradiend也在屏幕上移动),还有来自Java6的JPopupMenu的重要版本

image 图片

在此输入图像描述

from code 来自代码

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

You don't have to extend JPopupMenu class, just make your menu non-opaque and then make the JMenuItems transparent instead (and non-opaque). 您不必扩展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(); 
        } 
}

在此输入图像描述

OR, do the opposite, extend JPopupMenu to make it transparent and keep both the menu and items non-opaque (this way there will be no opaque border of the menu like above). 或者,相反,扩展JPopupMenu使其透明,并保持菜单和项目不透明(这样就不会像上面那样没有菜单的不透明边框)。

EDIT: 编辑:

Note that (unfortunately) it does not work when the popup menu exceeds the frame bounds, as @Durandal remarked. 请注意(不幸的是)当弹出菜单超出帧边界时它不起作用,正如@Durandal所说。

Though you could try to make some calculations and change location of popup (when needed) to keep it always inside the frame. 虽然您可以尝试进行一些计算并更改弹出窗口的位置(如果需要),以使其始终保持在框架内。

The problem with a popup menu is that it may be realized as a top-level container (Window), and a window is opaque, no matter what value you set with setOpaque(), its opaque. 弹出菜单的问题在于它可以实现为顶级容器(Window),并且窗口是不透明的,无论您使用setOpaque()设置什么值,它都是不透明的。 But windows can be made translucent, too. 但窗户也可以制成半透明的。

You can hack it by forcing the use of a heavyweight popup and brutally altering its opacity. 你可以通过强制使用重量级弹出窗口并残酷地改变其不透明度来破解它。 Try this as a starting base for experiments (Java7): 试试这个作为实验的起始基础(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();
            }
        }
    }

}

Note that it will not make submenus translucent! 请注意,它不会使子菜单半透明!

See this excellent 2008 article Translucent and Shaped Swing Windows by Kirill Grouchnikov. 请参阅Kirill Grouchnikov撰写的这篇优秀的2008年文章Translucent and Shaped Swing Windows

Based on examples given in the above article and code borrowed from the JGoodies project, you can install a custom popup Look & Feel using the following 2 classes: 基于上面文章中给出的示例和从JGoodies项目借来的代码,您可以使用以下两个类安装自定义弹出式外观​​:

  1. TranslucentPopup is the customized Popup, used by JPopupMenu: 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 is requried to install the custom Look and Feel: 需要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); } } 

The result is that all Popups (including JPopupMenu and perhaps also ToolTips) will now be Translucent, and optionally have a custom border: 结果是所有弹出窗口(包括JPopupMenu,也许还有工具提示)现在都是半透明的,并且可选地具有自定义边框: World Wind Context Menu示例应用程序上显示的半透明上下文菜单

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM