我想自定义JPopupMenu
的外观,所以我在i上创建了一个扩展JPopupMenu类的自定义类覆盖paintComponent
方法,就像我需要自定义的任何组件一样。< / p>
public class CustomPopupMenu extends JPopupMenu {
@Override
public paintComponent(Graphics g) {
//custom draw
}
}
我知道的唯一问题是我无法使JPopupMenu
透明。我虽然setOpaque(false)
就够了,但我错了。
如何让JPopupMenu
透明?
答案 0 :(得分:4)
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
(Gradiend也在屏幕上移动),带有JPopupMenu重要更改的版本,仍然来自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);
}
}
}
答案 1 :(得分:2)
您不必延长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所说。
虽然您可以尝试进行一些计算并更改弹出窗口的位置(如果需要),以使其始终保持在框架内。
答案 2 :(得分:2)
弹出菜单的问题在于它可能被实现为顶级容器(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();
}
}
}
}
请注意,不使子菜单半透明!
答案 3 :(得分:1)
请参阅Kirill Grouchnikov撰写的2008年优秀文章Translucent and Shaped Swing Windows。
根据上面文章中给出的示例和从JGoodies项目借来的代码,您可以安装自定义弹出窗口Look&amp;感觉使用以下两个类:
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);
}
}
需要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,也许还有工具提示)现在都是半透明的,并且可选地具有自定义边框: