如何获取在Java中启动弹出菜单的JTextField事件?

如何获取在Java中启动弹出菜单的JTextField事件?,java,events,swing,popup,jtextfield,Java,Events,Swing,Popup,Jtextfield,我有一个代表一天的JTextField,例如“Sunday”,当我用鼠标左键单击它时,它会改变背景颜色,当我用鼠标右键单击它时,会出现一个弹出菜单,当我单击菜单项后,例如“一月一日”,它会得到值,关闭菜单,然后更改背景颜色,我的代码如下所示: JTextField dayHeading=new JTextField("Su"); ...... final JPopupMenu Pmenu; JMenuItem menuItem; Pmenu=new JPopupM

我有一个代表一天的JTextField,例如“Sunday”,当我用鼠标左键单击它时,它会改变背景颜色,当我用鼠标右键单击它时,会出现一个弹出菜单,当我单击菜单项后,例如“一月一日”,它会得到值,关闭菜单,然后更改背景颜色,我的代码如下所示:

    JTextField dayHeading=new JTextField("Su");
......
    final JPopupMenu Pmenu;
    JMenuItem menuItem;
    Pmenu=new JPopupMenu();
    menuItem=new JMenuItem("1st of month");
    Pmenu.add(menuItem);
    menuItem=new JMenuItem("2nd of month");
    Pmenu.add(menuItem);
......
    menuItem.addMouseListener(new MouseAdapter()
    {
      public void mouseReleased(final MouseEvent e)
      {
        System.out.println(((JMenuItem)e.getComponent()).getText());
        onHeadingClicked(e);  // Error : java.lang.ClassCastException: javax.swing.JMenuItem cannot be cast to javax.swing.JTextField
                              // How to get the orininal JTextField event that started this pop up menu, so I can pass it onto  onHeadingClicked() ?
      }
    });
......
    dayHeading.setEditable(false);
    dayHeading.setFocusable(false);
    dayHeading.addMouseListener(new MouseAdapter()
    {
        public void mouseReleased(final MouseEvent evt)
        {
          if (SwingUtilities.isLeftMouseButton(evt)) onHeadingClicked(evt);
          else if (SwingUtilities.isRightMouseButton(evt)) Pmenu.show(evt.getComponent(),evt.getX(),evt.getY());
        }
    });

......
    void onHeadingClicked(final java.awt.event.MouseEvent evt)
    {
      final javax.swing.JTextField fld=(javax.swing.JTextField) evt.getSource();
...
    }

我的问题是:在menuItem.addMouseListener部分中,如何获取启动此弹出菜单的原始JTextField事件,以便我可以将其传递到onHeadingClicked()?

您将获得ClassCastException,因为mouselistener不在JTextField上,而是在JMenuItem上。它们是两个互不相关的不同组件,因此JMenuItem不知道JTextField“启动了它”,因此除非您自己进行关联,否则无法直接实现这一点

为什么不稍微更改一下类,而不是使用匿名适配器:

让你的类直接实现MouseListener

实现MouseListener接口的方法(主要是MouseRelease()、mousePressed()等),那些您不感兴趣的方法只需将它们保留为空(您仍然需要声明它们)

然后更改此选项:

menuItem.addMouseListener(new MouseAdapter()
    {
      public void mouseReleased(final MouseEvent e)
      {
        System.out.println(((JMenuItem)e.getComponent()).getText());
        onHeadingClicked(e);  // Error : java.lang.ClassCastException: javax.swing.JMenuItem cannot be cast to javax.swing.JTextField
                              // How to get the orininal JTextField event that started this pop up menu, so I can pass it onto  onHeadingClicked() ?
      }
    });
为此:

menuItem.addMouseListener(this);

通过这种方式,您可以访问类中的所有组件,并且可以访问JTextField对象。

我想到了一个快速解决方案:

  MouseEvent Right_Click_Mouse_Event;

...
    menuItem.addMouseListener(new MouseAdapter()
    {
      public void mouseReleased(final MouseEvent e)
      {
        Out(((JMenuItem)e.getComponent()).getText());
        onHeadingClicked(Right_Click_Mouse_Event,((JMenuItem)e.getComponent()).getText());
      }
    });
...
      dayHeading.addMouseListener(new MouseAdapter()
      {
        public void mouseReleased(final MouseEvent evt)
        {
          if (SwingUtilities.isLeftMouseButton(evt)) onHeadingClicked(evt,"");
          else if (SwingUtilities.isRightMouseButton(evt))
          {
            Pmenu.show(evt.getComponent(),evt.getX(),evt.getY());
            Right_Click_Mouse_Event=evt;
          }
        }
      });
...
  void onHeadingClicked(final java.awt.event.MouseEvent evt,String Order_In_Month)
  {
    final javax.swing.JTextField fld=(javax.swing.JTextField) evt.getSource();
...
  }

工作正常。

请阅读上的Swing教程中的部分以了解工作示例。MouseListener仅用于显示弹出窗口,不处理菜单项的选择。您需要向每个菜单项添加一个ActionListener来处理选择

在这种情况下,ActionEvent将是菜单项。因此,您应该能够使用ActionEvent的getSource()方法来获取菜单项。然后可以使用getParent()方法来获取弹出菜单。最后,可以使用getInvoker()方法获取文本字段。比如:

JMenuItem mi = (JMenuItem)e.getSource();
JPopupMenu popup = (JPopupMenu)mi.getParent();
JTextField tf = (JTextField)popup.getInvoker();
class SelectAll extends TextAction
{
    public SelectAll()
    {
        super("Select All");
    }

    public void actionPerformed(ActionEvent e)
    {
        JTextComponent component = getFocusedComponent();
        component.selectAll();
    }
}
但是,更好的方法是使用操作创建菜单项。本教程还有一个关于“如何使用动作”的部分,其中包含解释和示例。在本例中,您将扩展TextAction。现在,当调用该操作时,只需使用该操作的getFocusedComponent()方法来获取文本字段。比如:

JMenuItem mi = (JMenuItem)e.getSource();
JPopupMenu popup = (JPopupMenu)mi.getParent();
JTextField tf = (JTextField)popup.getInvoker();
class SelectAll extends TextAction
{
    public SelectAll()
    {
        super("Select All");
    }

    public void actionPerformed(ActionEvent e)
    {
        JTextComponent component = getFocusedComponent();
        component.selectAll();
    }
}
我是这样做的:

private void CommonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {                                           
    JMenuItem menuItem = (JMenuItem)evt.getSource();         // source is clicked JMenuItem
    JPopupMenu popupMenu = (JPopupMenu)menuItem.getParent(); // get parent JPopupMenu
    Component component = popupMenu.getInvoker();            // who called JPopupMenu?
    System.out.println(component.getName());                 // get component name
}

要使其正常工作,您需要命名具有JPopupMenus的组件。这不是正确的解决方案。我同意,但这何时会导致问题?我没有仔细查看您的代码,因此我不知道您做了哪些更改。主要的问题是没有人会理解代码,因为有标准的方法来解决这个问题,正如在教程中演示的那样。但我想一个大问题是,用户将无法使用键盘选择菜单项。你永远不能假设人们只会使用鼠标。事实上,高级用户总是喜欢使用键盘。不管这是否有效,这是一个相当混乱的黑客行为。将以前的鼠标单击事件(当显示菜单时)传递给将来的事件(当选择菜单项时)只会导致错误和混乱。不用匿名适配器,只需自己实现MouseListener,就可以以一种简单的面向对象的干净方式访问所有类!匿名适配器只是在简单直接的情况下使用的,像这样的场景开始指向有一个正确的类正确地实现接口。