簡體   English   中英

如何讓JPopupMenu透明化?

[英]How can i make a JPopupMenu transparent?

我想自定義JPopupMenu的外觀,所以我在i上創建了一個擴展JPopupMenu類的自定義類覆蓋了paintComponent方法,就像我需要自定義的任何組件一樣。

public class CustomPopupMenu extends JPopupMenu {

    @Override
    public paintComponent(Graphics g) {
        //custom draw
    }
}

我知道的唯一問題是我無法使JPopupMenu透明化。 我雖然setOpaque(false)就夠了,我錯了。

如何讓JPopupMenu透明化?

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);
            }
        });
    }
}

編輯

TranslucencyNimbus L&F有趣支持,特別是Painter再現非常正確的Color (Gradiend也在屏幕上移動),還有來自Java6的JPopupMenu的重要版本

圖片

在此輸入圖像描述

來自代碼

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所說。

雖然您可以嘗試進行一些計算並更改彈出窗口的位置(如果需要),以使其始終保持在框架內。

彈出菜單的問題在於它可以實現為頂級容器(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();
            }
        }
    }

}

請注意,它不會使子菜單半透明!

請參閱Kirill Grouchnikov撰寫的這篇優秀的2008年文章Translucent and Shaped Swing Windows

基於上面文章中給出的示例和從JGoodies項目借來的代碼,您可以使用以下兩個類安裝自定義彈出式外觀​​:

  1. 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); } } 
  2. 需要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,也許還有工具提示)現在都是半透明的,並且可選地具有自定義邊框: World Wind Context Menu示例應用程序上顯示的半透明上下文菜單

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM