Как я могу сделать JPopupMenu прозрачным?
Я хотел бы настроить внешний вид JPopupMenu
поэтому я сделал пользовательский класс, расширяющий класс JPopupMenu, я переопределил paintComponent
метод, как я бы сделал для любого компонента, который мне нужно настроить.
public class CustomPopupMenu extends JPopupMenu {
@Override
public paintComponent(Graphics g) {
//custom draw
}
}
Единственная проблема, которую я имею право знать, это то, что я не могу JPopupMenu
прозрачный. Хотя я setOpaque(false)
было бы достаточно, я был неправ.
Как я могу сделать JPopupMenu
прозрачный?
4 ответа
Проблема с всплывающим меню состоит в том, что оно может быть реализовано как контейнер верхнего уровня (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);
}
});
}
}
РЕДАКТИРОВАТЬ
интересная поддержка 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);
}
}
}
Вам не нужно расширять 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.
Хотя вы можете попытаться сделать некоторые расчеты и изменить местоположение всплывающего окна (при необходимости), чтобы оно всегда оставалось внутри фрейма.
Посмотрите эту прекрасную статью Кирилла Гручникова " Полупрозрачные и фасонные окна" 2008 года.
На основе примеров, приведенных в статье выше, и кода, заимствованного из проекта JGoodies, вы можете установить собственное всплывающее окно Look & Feel, используя следующие 2 класса:
TranslucentPopup - это настраиваемое всплывающее окно, используемое JPopupMenu:
/** * 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 и, возможно, также всплывающие подсказки) теперь будут полупрозрачными и при желании будут иметь собственную границу: