我想自定义JPopupMenu的外观,所以我创建了一个自定义类来扩展JPopupMenu类,覆盖了paintComponent方法,就像我对任何需要自定义的组件所做的那样。
public class CustomPopupMenu extends JPopupMenu {
@Override
public paintComponent(Graphics g) {
//custom draw
}
}我唯一正确知道的问题是我不能让JPopupMenu变得透明。我以为setOpaque(false)就足够了,我错了。
怎样才能让JPopupMenu变得透明?
发布于 2012-10-09 22:17:38
弹出式菜单的问题是,它可能被实现为顶级容器(窗口),而窗口是不透明的,无论您使用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-09 21:57:54
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-09 22:13:33
您不必扩展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所说的那样。
虽然您可以尝试进行一些计算和更改弹出窗口的位置(当需要时),以使其始终保持在框架内。
https://stackoverflow.com/questions/12801035
复制相似问题