【问题标题】:JMenuItem and JMenu used outside of a JMenu component - JMenu sub-menu not workingJMenuItem 和 JMenu 在 JMenu 组件之外使用 - JMenu 子菜单不起作用
【发布时间】:2015-04-24 19:26:06
【问题描述】:

我正在尝试创建自定义弹出菜单。

硬性要求如下: 1) 讲话泡泡形状 2) 透明度 3) 菜单一直打开,直到通过关闭按钮关闭

我已经设法实现了上述所有三个,但是当我尝试添加一个普通的子菜单时,它就不起作用了。它呈现为好像它是一个子菜单,但似乎没有注册鼠标交互。我什至尝试直接将 ActionListener 添加到菜单中,但没有效果。

** 编辑 ** 根据反馈添加新样本,因为缺少布局和颜色不适用于我要解决的问题,原始样本遵循新样本

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;

public class CustomMenu extends JFrame
{
    public CustomMenu()
    {
        super();
        setUndecorated(true);
        setAlwaysOnTop(true);
        setOpacity(0.75f);
        setSize(100, 110);
        setLocation(800, 600);
        setShape(new RoundRectangle2D.Float(0, 0, 100, 110, 25, 25));
        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        setBackground(Color.black);
        JButton closeButton = new JButton();
        closeButton.setSize(16, 16);
        closeButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                CustomMenu.this.dispose();
            }
        });
        closeButton.setLocation(75, 5);
        getContentPane().add(closeButton);

        JLabel label = new JLabel("Menu Title");
        label.setSize(90, 25);
        getContentPane().add(label);
        JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
        separator.setSize(90,5);
        getContentPane().add(separator);

        JMenu menu = new JMenu("Sub Menu");

        JMenuItem menuItem = new JMenuItem("Sub Menu Item One");
        menuItem.setSize(100, 25);
        menu.add(menuItem);

        menuItem = new JMenuItem("Sub Menu Item Two");
        menuItem.setSize(100, 25);
        menu.add(menuItem);

        menu.setSize(100, 25);
        getContentPane().add(menu);

        menuItem = new JMenuItem("Menu Item One");
        menuItem.setSize(100, 25);
        getContentPane().add(menuItem);

        menuItem = new JMenuItem("Menu Item Two");
        menuItem.setSize(100, 25);
        getContentPane().add(menuItem);

        menuItem = new JMenuItem("Menu Item Three");
        menuItem.setSize(100, 25);
        getContentPane().add(menuItem);
    }

    public static void main(String args[])
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new CustomMenu().setVisible(true);
            }
        });
    }
}

我能想到的最简单的自包含示例如下。提前感谢您的任何帮助。

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;

public class CustomMenu extends JFrame
{
    public CustomMenu()
    {
        super();
        setUndecorated(true);
        setAlwaysOnTop(true);
        setOpacity(0.75f);
        setSize(100, 110);
        setLocation(800, 600);
        setShape(new RoundRectangle2D.Float(0, 0, 100, 110, 25, 25));
        setLayout(null);
        setBackground(Color.black);
        JButton closeButton = new JButton();
        closeButton.setSize(16, 16);
        closeButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                CustomMenu.this.dispose();
            }
        });
        closeButton.setLocation(75, 5);
        add(closeButton);

        JLabel label = new JLabel("Menu Title");
        int y = 0;
        label.setLocation(10, y);
        label.setSize(90, 25);
        add(label);
        y += label.getHeight();
        JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
        separator.setSize(90,5);
        separator.setLocation(5, y);
        add(separator);
        y += separator.getHeight();

        JMenu menu = new JMenu("Sub Menu");

        JMenuItem menuItem = new JMenuItem("Sub Menu Item One");
        menuItem.setBackground(new Color(0,0,0,0));
        menuItem.setSize(100, 25);
        menuItem.setLocation(0,0);
        menu.add(menuItem);

        menuItem = new JMenuItem("Sub Menu Item Two");
        menuItem.setBackground(new Color(0,0,0,0));
        menuItem.setSize(100, 25);
        menuItem.setLocation(0,25);
        menu.add(menuItem);

        menu.setBackground(new Color(0,0,0,0));
        menu.setSize(100, 25);
        menu.setLocation(-1, y);
        add(menu);
        y += menu.getHeight();

        menuItem = new JMenuItem("Menu Item One");
        menuItem.setBackground(new Color(0,0,0,0));
        menuItem.setSize(100, 25);
        menuItem.setLocation(-1, y);
        add(menuItem);
        y += menuItem.getHeight();

        menuItem = new JMenuItem("Menu Item Two");
        menuItem.setBackground(new Color(0,0,0,0));
        menuItem.setSize(100, 25);
        menuItem.setLocation(-1, y);
        add(menuItem);
        y += menuItem.getHeight();

        menuItem = new JMenuItem("Menu Item Three");
        menuItem.setBackground(new Color(0,0,0,0));
        menuItem.setSize(100, 25);
        menuItem.setLocation(-1, y);
        add(menuItem);
    }

    public static void main(String args[])
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new CustomMenu().setVisible(true);
            }
        });
    }
}

【问题讨论】:

  • 我看到的第一个问题是船体布局,其次是负位置的使用
  • 另外,Swing 不处理透明色
  • 我需要精确定位我正在制作的菜单上的所有元素,因此是空布局。不会有调整大小,所以层管理器头痛是不值得的。
  • 如果您运行我提供的示例,您会发现 Swing 确实可以很好地处理透明色。

标签: java swing transparency jmenu jmenuitem


【解决方案1】:

问题...

  1. 空布局
  2. 负布局位置
  3. 基于 Alpha 的背景颜色

Swing 不喜欢其组件的负位置

Swing 不能渲染基于 alpha 的背景颜色,它只知道如何渲染不透明和完全透明的组件。使用基于 alpha 的颜色会阻止 swing 更新组件下方的区域,这会导致奇怪的油漆伪影和其他问题

解决方案...

  1. 使用适当的布局管理器
  2. 见第 1 点。
  3. 使用setOpaque。如果您需要半透明背景,则需要创建一个自定义组件并覆盖其paintComponent 方法并自己绘制背景

应该注意的是,您实际上可以控制子菜单使用的弹出窗口,这些是在 api 的内部深处创建的(我认为甚至可以通过静态方法,但我已经有一段时间没有挖掘它了深)

【讨论】:

  • 我真的很讨厌试图找到一个有效的布局管理器。框布局关闭,但不允许我将关闭按钮定位在第一个元素上。此框架不会调整大小,因此我无法从布局管理器中获得任何好处。
  • 至于半透明背景,我需要的是所有组件都是半透明的。我用 JFrame 得到了这个,我只是不希望背景颜色出现,因此完全透明的颜色。
  • 子菜单根本不起作用,有什么想法吗?
  • 1- 使用布局管理器的组合。也许是 BorderLayout 和 GridBagLayout。我认为在外观代码的某个地方隐藏了一个“菜单布局”; 2-正如我所说,如果你想要透明度,你需要将组件设置为完全透明并覆盖它们的paintComponet方法并自己填充背景;至于子菜单,恐怕你不走运,因为用于查找播放它们的“窗口”是由系统生成的,并且深埋在核心代码中。我能想到的唯一一件事就是从头开始自己生成所有内容,包括菜单项
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 1970-01-01
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多