源作:陈思羽.
更新:龚德伟. 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("Author:\r\n");
sbMsg.append("陈思羽,龚德伟\r\n");
sbMsg.append("@history\r\n");
sbMsg.append("2008-7-20");
contentPane.add(new JScrollPane(new JTextArea(sbMsg.toString())));
frame.setContentPane(contentPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}