【问题标题】:scope of the mouse adapter鼠标适配器的范围
【发布时间】:2012-04-15 11:02:44
【问题描述】:

我想知道在这种情况下 MouseAdapter 的范围是什么。

class foo extends JPanel()
{
  private JMenu edit = new JMenu();
  public foo()
  {
      this.edit.getItem(0).addMouseListener(new MouseAdapter(){ 
          @Override
          public void mouseClicked(MouseEvent e) {
              if (e.getClickCount() == 1) {
                  edit.getItem(0).setEnabled(true);
              }
          } 
      });
  }
}

我认为 MouseAdapter 可以访问变量 edit,因为新声明的 MouseAdapter 是类 foo 的内部类。但是,它找不到变量edit。如果我明确声明一个内部类并实现,比如说,MouseAdapter 接口或其他什么,它可以从其中检测变量 edit。所以我的问题是 new MouseAdpater() 的范围是什么 有吗?此外,有人知道这方面的好书吗?非常感谢。顺便说一句,我得到的错误是局部变量是从内部类访问的,需要将其声明为final

【问题讨论】:

  • class foo() { ??? ...如果您希望我们认真对待您的问题,请发布真实代码,而不是像上面那样糟糕的代码。但是,是的,从您的 mouseClicked 方法中可以看到 bar 。这段代码没有问题。
  • 我修复了代码以使其更清晰,感谢您的提示

标签: java swing jmenu mouse-listeners


【解决方案1】:

1)edit.getItem(0)如果存在则返回拳头JMenuItem,否则返回IllegalArgumentException

2) this.edit.getItem(0),不是返回成员的类

3) edit.getItem(0).addMouseListener(new MouseAdapter(){ 是相反的,因为 JMenuJMenuItem 已经正确实现了 MouseEvents,为了更好的解决方法,您必须查看 ButtonModel

4) 没有理由scope of the mouse adapter

5) 要监听来自JMenu(不是JMenuItem)的事件,请查看MenuListener

【讨论】:

  • 感谢您提供的信息,只是一个简单的问题,当我想听的是鼠标单击 JMenuItem 时,我应该将 MenuListner 添加到 JMenu 或 JMenuItem。
  • 对于JButton的JComponents有ButtonModel,返回有趣的测试、通知和监听方法
  • 谢谢,我一直想知道那些 Model 是什么,你能给我一个很好的阅读指南吗?谢谢
  • @Clint Hui 每个JComponents都有Models,只有JTextComponents有Document
【解决方案2】:

如您所料,您的匿名内部类确实存在于其父对象的范围内。 范围不是问题。

正如错误消息所暗示的,匿名内部类只能访问其父级的“编辑”成员,前提是该成员被声明为 final。

所以,改变

  private JMenu edit = new JMenu();

  private final JMenu edit = new JMenu();

它应该可以工作。

【讨论】:

    【解决方案3】:

    要回答您的问题,您需要了解有关 JVM 是如何工作的基础知识。 当编译包含内部类的类时,生成的字节码实际上并没有将内部类实现为类中的类。

    为什么会出错:局部变量是从内部类访问的,需要将其声明为 final

    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.JMenu;
    import javax.swing.JPanel;
    
    public class foo extends JPanel
    {  
      public foo()
      {
        final JMenu edit = new JMenu();
        edit.getItem(0).addMouseListener(new MouseAdapter(){ 
        @Override
            public void mouseClicked(MouseEvent e) 
            {
                if (e.getClickCount() == 1) {
                    edit.getItem(0).setEnabled(true);
                }
            } 
        });
      }
    }
    

    当你编译你的这个程序时,会创建两个文件,Foo.class 和 Foo$1.class。所以现在你的问题来了,因为Second 类即foo$1.class 不知道Variable edit 存在于First 类中,即foo.class

    那么如何解决这个问题呢? JVM 所做的是,要求开发人员将外部类的变量声明为 final

    现在这已经完成,现在 JVM 悄悄地在第二个编译的类文件中放置了一个名为 val$edit 的隐藏变量,这是从 javap 得到的输出

    foo.class 的输出

    C:\Mine\JAVA\J2SE\folder>javap foo.class
    Compiled from "foo.java"
    public class foo extends javax.swing.JPanel {
      public foo();
    }
    

    现在,编辑是构造函数的本地,因此输出如上。

    C:\Mine\JAVA\J2SE\folder>javap foo$1.class
    Compiled from "foo.java"
    class foo$1 extends java.awt.event.MouseAdapter {
      final javax.swing.JMenu val$edit;
      final foo this$0;
      foo$1(foo, javax.swing.JMenu);
      public void mouseClicked(java.awt.event.MouseEvent);
    }
    

    Variable val$edit 分配了与分配给 edit 相同的值,因为现在编译器知道该值不能更改,因为它已被声明为 final,因此这次它可以工作。

    现在,如果我将 edit VariableLocal 更改为 Instance 会怎样。现在类的对象知道关于这个变量edit的一切,如果它被改变的话。所以同样改变上面的程序我们得到:

    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.JMenu;
    import javax.swing.JPanel;
    
    public class foo extends JPanel
    {  
        JMenu edit = new JMenu();
    
        public foo()
        {   
            edit.getItem(0).addMouseListener(new MouseAdapter(){ 
            @Override
                public void mouseClicked(MouseEvent e) 
                {
                if (e.getClickCount() == 1) {
                        edit.getItem(0).setEnabled(true);
                    }
                } 
            });
        }
    }
    

    在这种情况下,我们不应该将其声明和定义为final,因为在这种情况下,由于Variable 是整个类的本地,Variable 被发送到内部类与Object Referencethis

    C:\Mine\JAVA\J2SE\folder>javap foo.class
    Compiled from "foo.java"
    public class foo extends javax.swing.JPanel {
      javax.swing.JMenu edit;
      public foo();
    }
    

    这是Variable 在这种情况下的发送方式,即 this$0:

    C:\Mine\JAVA\J2SE\folder>javap foo$1.class
    Compiled from "foo.java"
    class foo$1 extends java.awt.event.MouseAdapter {
      final foo this$0;
      foo$1(foo);
      public void mouseClicked(java.awt.event.MouseEvent);
    }
    

    据我说,这似乎是解释,这种情况是如何运作的。 刚才我在网上找到了这个关于Mystery of Accessibility in Local Inner Classes的精彩解释,也许这会帮助你更好地了解情况:-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-14
      • 2013-01-24
      • 2013-05-14
      • 1970-01-01
      • 2017-11-30
      • 2013-05-23
      相关资源
      最近更新 更多