源作:陈思羽.
更新:龚德伟. 2008.07.20
效果图

更新的内容:
优化了paint方法,不需要每次都创建一个BufferedImage.
修正了鼠标开时时菜单项背景不会变成半透明的问题
支持菜单普通情况下和鼠标选中时两种半透明设定
修正鼠标选中菜单时,文字变成不透明
import
java.awt.AlphaComposite;
import
java.awt.Color;
import
java.awt.Graphics;
import
java.awt.Graphics2D;
import
java.awt.Rectangle;

import
javax.swing.ButtonModel;
import
javax.swing.JComponent;
import
javax.swing.JMenu;
import
javax.swing.JMenuItem;
import
javax.swing.plaf.ComponentUI;
import
javax.swing.plaf.basic.BasicMenuItemUI;


/** */
/**
* 一个支持半透明的菜单UI
*
*
@author
陈思羽,龚德伟
* @history 2008-7-20
*
@see
<a href="
http://www.blogjava.net/chensiyu04/articles/201425.html
">
* 在试牛刀(设置半透明的JMenuBar)</a>
*/

public
class
CustomMenuItemUI
extends
BasicMenuItemUI
{

public
static
ComponentUI createUI(JComponent c)
{
return
new
CustomMenuItemUI();
}


/** */
/**
菜单的透明度
*/
private
static
float
alpha
=
0.5f
;
private
static
float
selectionAlpha
=
0.8f
;


public
static
float
getAlpha()
{
return
alpha;
}


public
static
void
setAlpha(
float
_alpha)
{
alpha
=
_alpha;
}

@Override

public
void
installUI(JComponent c)
{
super
.installUI(c);
//
设为透明,这样才会更新菜单低下的内容(这个请了解Opaque的作用)
menuItem.setOpaque(
false
);
}


public
void
paint(Graphics g, JComponent comp)
{
//
创建一个graphics的副本
Graphics2D gx
=
(Graphics2D) g.create();
//
alpha 就是透明度.值越小 透明度越大
gx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
//
将控件画到半透明 的画布上
super
.paint(gx, comp);
//
graphics使用后要销毁,这是良好习惯
gx.dispose();
}


/**/
/*
* 重写了背景的绘制方法,不管Opaque的属性,只按不透明方式画菜单背景
*/
@Override

protected
void
paintBackground(Graphics g, JMenuItem menuItem, Color bgColor)
{
ButtonModel model
=
menuItem.getModel();
Color oldColor
=
g.getColor();
int
menuWidth
=
menuItem.getWidth();
int
menuHeight
=
menuItem.getHeight();

if
(model.isArmed()
||
(menuItem
instanceof
JMenu
&&
model.isSelected()))
{
Graphics2D g2
=
(Graphics2D) g.create();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, selectionAlpha));
g2.setColor(bgColor);
g2.fillRect(
0
,
0
, menuWidth, menuHeight);

}
else
{
g.setColor(menuItem.getBackground());
g.fillRect(
0
,
0
, menuWidth, menuHeight);
}
g.setColor(oldColor);
}

@Override

protected
void
paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text)
{
ButtonModel model
=
menuItem.getModel();
//
鼠标移动菜单时文字不透明

if
(model.isArmed()
||
model.isSelected())
{
Graphics2D g2
=
(Graphics2D) g.create();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1.0f
));
super
.paintText(g2, menuItem, textRect, text);
g2.dispose();

}
else
{
super
.paintText(g, menuItem, textRect, text);
}
}


/** */
/**
* 设置选中时是否透明
*
@param
b
*/

public
static
void
setSelectionAlpha(
float
alpha)
{
selectionAlpha
=
alpha;
}
}
import
javax.swing.JComponent;
import
javax.swing.JPanel;
import
javax.swing.JPopupMenu;
import
javax.swing.Popup;
import
javax.swing.plaf.ComponentUI;
import
javax.swing.plaf.basic.BasicPopupMenuUI;


public
class
CustomPopupMenuUI
extends
BasicPopupMenuUI
{

public
static
ComponentUI createUI(JComponent c)
{
return
new
CustomPopupMenuUI();
}

public
void
installUI(JComponent c)
{
super
.installUI(c);
popupMenu.setOpaque(
false
);
}

public
Popup getPopup(JPopupMenu popup,
int
x,
int
y)
{
Popup pp
=
super
.getPopup(popup,x,y);
JPanel panel
=
(JPanel)popup.getParent();
panel.setOpaque(
false
);
return
pp;
}
}
import
javax.swing.Box;
import
javax.swing.BoxLayout;
import
javax.swing.JFrame;
import
javax.swing.JLabel;
import
javax.swing.JMenu;
import
javax.swing.JMenuBar;
import
javax.swing.JMenuItem;
import
javax.swing.JPanel;
import
javax.swing.JScrollPane;
import
javax.swing.JSeparator;
import
javax.swing.JSlider;
import
javax.swing.JTextArea;
import
javax.swing.UIManager;
import
javax.swing.event.ChangeEvent;
import
javax.swing.event.ChangeListener;


/** */
/**
* 半透明的菜单测试类
*
*
@author
陈思羽,龚德伟
* @history 2008-7-20
*
@see
<a href="
http://www.blogjava.net/chensiyu04/articles/201425.html
"> * 在试牛刀(设置半透明的JMenuBar)<
* /a>
*/

public
class
MenuTest
{

public
static
void
main(String[] args)
throws
Exception
{
//
这样把JFrame上所有JMenuBar的外观全设置为上面两个类已经写好的,这两句必须放在JMenuBar的前面
//
具体放在哪个方法里随便你
UIManager.put(
"
PopupMenuUI
"
,
"
CustomPopupMenuUI
"
);
//
自己看API,
UIManager.put(
"
MenuItemUI
"
,
"
CustomMenuItemUI
"
);
JFrame frame
=
new
JFrame();
JMenuBar mb
=
new
JMenuBar();
frame.setJMenuBar(mb);
JMenu menu
=
new
JMenu(
"
File
"
);
mb.add(menu);
menu.add(
new
JMenuItem(
"
Open
"
));
menu.add(
new
JMenuItem(
"
Save
"
));
menu.add(
new
JMenuItem(
"
Close
"
));
menu.add(
new
JMenuItem(
"
Exit
"
));
menu
=
new
JMenu(
"
Edit
"
);
mb.add(menu);

//
如果你把UIManager.put("PopupMenuUI","CustomPopupMenuUI");
//
UIManager.put("MenuItemUI","CustomMenuItemUI");
//
这两句在上面删掉 把他们放在这里 那么只有从这往下的JMenuITem可以为透明 以上的则无效果
menu.add(
new
JMenuItem(
"
Cut
"
));
menu.add(
new
JMenuItem(
"
Copy
"
));
menu.add(
new
JMenuItem(
"
Paste
"
));
menu.add(
new
JMenuItem(
"
Paste Special..
"
));
JPanel contentPane
=
new
JPanel();
BoxLayout layout
=
new
BoxLayout(contentPane, BoxLayout.Y_AXIS);
contentPane.setLayout(layout);
contentPane.add(Box.createVerticalGlue());
JSlider alphaSlider
=
new
JSlider(JSlider.HORIZONTAL);
contentPane.add(
new
JLabel(
"
菜单背景不透明度:
"
));
contentPane.add(alphaSlider);

alphaSlider.addChangeListener(
new
ChangeListener()
{

public
void
stateChanged(ChangeEvent e)
{
JSlider slider
=
(JSlider) e.getSource();
float
alpha
=
(
1.0f
*
slider.getValue()
/
100
);
CustomMenuItemUI.setAlpha(alpha);
slider.setToolTipText(
"
不透明:
"
+
slider.getValue());
}
}
);
contentPane.add(
new
JSeparator(JSeparator.HORIZONTAL));
JSlider selectionAlphaSlider
=
new
JSlider(JSlider.HORIZONTAL);
contentPane.add(
new
JLabel(
"
菜单选中时背景不透明度:
"
));
contentPane.add(selectionAlphaSlider);

selectionAlphaSlider.addChangeListener(
new
ChangeListener()
{

public
void
stateChanged(ChangeEvent e)
{
JSlider slider
=
(JSlider) e.getSource();
float
alpha
=
(
1.0f
*
slider.getValue()
/
100
);
CustomMenuItemUI.setSelectionAlpha(alpha);
slider.setToolTipText(
"
不透明:
"
+
slider.getValue());
}
}
);
contentPane.add(
new
JSeparator(JSeparator.HORIZONTAL));
contentPane.add(Box.createVerticalGlue());
StringBuilder sbMsg
=
new
StringBuilder();
sbMsg.append(
"
CustomMenuItemUI\r\n
"
);
sbMsg.append(
"
一个支持半透明的菜单UI \r\n
"
);
sbMsg.append(
"
\r\n
"
);
sbMsg.append(
"
See Also:\r\n
"
);
sbMsg.append(
"
在试牛刀(设置半透明的JMenuBar)\r\n
"
);
sbMsg.append(