如何让JPopupMenu透明化?

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

 public class CustomPopupMenu extends JPopupMenu { @Override public paintComponent(Graphics g) { //custom draw } } 

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

如何让JPopupMenu透明化?

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

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

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

编辑

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

图片

在此处输入图像描述

来自代码

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

您不必扩展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所说。

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

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

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

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

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