【问题标题】:how to fire MouseListener event methods if it's already running如果 MouseListener 已经在运行,如何触发事件方法
【发布时间】:2016-01-05 18:17:26
【问题描述】:

在我的代码中我有:

具有普通 JPanel 的 JFrame,其中包含一些 JComponent 对象。 这些 JComponent 具有: - JTextFields 列表。 - 一个监听器,它在 mouseEntered 触发时突出显示其边框,并在 mouseExited 触发时隐藏它。 由于当光标越过嵌套在 JComponent 中的 jtextField 时也会触发 mouseExited 方法,因此 mouseExited 方法的实现会在隐藏边框之前检查事件的光标位置是否在 JComponentArea 之外:

问题是:

如果您缓慢移动鼠标,代码似乎可以正常工作,但如果您在组件之间快速移动鼠标,有时 JComponent 的边框不会隐藏。 我认为这可能是因为当光标越过嵌套的 textField 时触发了 mouseExited,然后当光标在 JComponent 之外时再次触发,但我不确定真正的问题是什么。 提前感谢您的任何提示或帮助!

守则:

已针对上述问题编写代码。这里是 Jcomponent 类(MyContainer)和包含 Main 的类(MyClass):

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class MyClass {

    public static void main(String[] args)  {       
        SwingUtilities.invokeLater(new Runnable() {
            public void run(){   
                int i=0;
                //mainWindow
                    JFrame mainWindow = new JFrame("MyFrame");
                    mainWindow.setLayout(new BorderLayout());
                    mainWindow.setMinimumSize(new Dimension(300,300));

                    JPanel viewPort = new JPanel();
                    viewPort.setLayout(new FlowLayout(FlowLayout.LEFT));

                    MyContainer one = new MyContainer();
                    MyContainer two = new MyContainer();
                    MyContainer three = new MyContainer();

                    viewPort.add(one);
                    viewPort.add(two);
                    viewPort.add(three);
                    mainWindow.add(viewPort,BorderLayout.CENTER);
                    mainWindow.setVisible(true);
            }
        });
    }

}





import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JTextField;

    @SuppressWarnings("serial")
    public  class MyContainer extends JComponent {
            JTextField text1 ;
            JTextField text2 ;
            JTextField text3 ;

            public MyContainer(){
                super.setLayout(new FlowLayout(FlowLayout.LEFT));
                super.setPreferredSize(new Dimension(200,50));
                super.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
                super.setBackground(Color.green);

                text1 = new JTextField("LABEL_1");
                text1.setPreferredSize(new Dimension(60,30));
                text1.setEditable(false);
                this.add(text1);

                text2 = new JTextField("LABEL_2");
                text2.setPreferredSize(new Dimension(60,30));
                text2.setEditable(false);
                this.add(text2);

                text3 = new JTextField("LABEL_3");
                text3.setPreferredSize(new Dimension(60,30));
                text3.setEditable(false);
                this.add(text3);

                addListener();
            }

            private void addListener() {
                this.addMouseListener(new MouseListener() {
                    @Override
                    public void mouseEntered(MouseEvent e) {
                        MyContainer.this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
                    }

                    @Override
                    public void mouseExited(MouseEvent e) {
                        Rectangle r = e.getComponent().getBounds();
                        Point p = e.getPoint();
                        if( p.x < 0 || p.y < 0 || p.x >= r.width || p.y >= r.height)
                            MyContainer.this.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
                    }

                    @Override public void mouseClicked(MouseEvent e) { /*NOTHING*/ }
                    @Override public void mouseReleased(MouseEvent e) { /*NOTHING*/ }
                    @Override public void mousePressed(MouseEvent e) { /*NOTHING*/ }
                });         
            }
        }

【问题讨论】:

  • These 答案可能对您有用。

标签: java swing mouselistener


【解决方案1】:

这是使用MyContainer.this.dispatchEvent(SwingUtilities.convertMouseEvent(JTextField, e, MyContainer.this)); 的一种可能实现方式:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class MyClass2 {
  public static void main(String[] args)  {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        int i = 0;
        //mainWindow
        JFrame mainWindow = new JFrame("MyFrame");
        mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        mainWindow.setMinimumSize(new Dimension(300, 300));

        JPanel viewPort = new JPanel();
        viewPort.setLayout(new FlowLayout(FlowLayout.LEFT));

        MyContainer one = new MyContainer();
        MyContainer two = new MyContainer(true);
        viewPort.add(makeTitledPanel(one, "move it fast: NG?"));
        viewPort.add(makeTitledPanel(two, "move it fast: OK?"));
        mainWindow.add(viewPort, BorderLayout.CENTER);
        mainWindow.setVisible(true);
      }
    });
  }
  private static JComponent makeTitledPanel(JComponent c, String title) {
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createTitledBorder(title));
    p.add(c);
    return p;
  }
}

class MyContainer extends JComponent {
  JTextField text1 ;
  JTextField text2 ;
  JTextField text3 ;
  private final boolean flag;
  public MyContainer() {
    this(false);
  }
  public MyContainer(boolean flag) {
    super();
    this.flag = flag;

    super.setLayout(new FlowLayout(FlowLayout.LEFT));
    super.setPreferredSize(new Dimension(200, 50));
    super.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
    super.setBackground(Color.green);

    text1 = new JTextField("LABEL_1");
    text2 = new JTextField("LABEL_2");
    text3 = new JTextField("LABEL_3");

    MouseListener l = new MouseEventConverter();
    for (JTextField f : Arrays.asList(text1, text2, text3)) {
      f.setPreferredSize(new Dimension(60, 30));
      f.setEditable(false);
      if (flag) {
        f.addMouseListener(l);
      }
      this.add(f);
    }
    this.addMouseListener(new MouseAdapter() {
      @Override
      public void mouseEntered(MouseEvent e) {
        MyContainer.this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
      }
      @Override
      public void mouseExited(MouseEvent e) {
        Rectangle r = e.getComponent().getBounds();
        Point p = e.getPoint();
        if (p.x < 0 || p.y < 0 || p.x >= r.width || p.y >= r.height) {
          MyContainer.this.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        }
      }
    });
  }
}

class MouseEventConverter extends MouseAdapter {
  @Override public void mouseEntered(MouseEvent e) {
    dispatchMouseEvent(e);
  }
  @Override public void mouseExited(MouseEvent e) {
    dispatchMouseEvent(e);
  }
  private void dispatchMouseEvent(MouseEvent e) {
    Component c = e.getComponent();
    Component p = SwingUtilities.getUnwrappedParent(c);
    p.dispatchEvent(SwingUtilities.convertMouseEvent(c, e, p));
  }
}

【讨论】:

    【解决方案2】:

    我建议不要使用静态方法,尽管我不确定按照您的方式进行操作会产生什么实际影响。我会推荐

    public void mouseEntered(MouseEvent e) {
        ((MyContainer) e.getSource()).setBorder(...)
    }
    
    // and so forth
    

    此外,问题可能出在您的 mouseExited 方法上。而不是使用.getBounds(),我建议使用instanceof

    if(e.getSource() instanceof MyContainer) {
        // do the stuff
    } else {
        // do nothing
    }
    

    或者:

    if(!(e.getSource() instanceof JTextField)) {
        // do the stuff
    } else {
        // do nothing
    }
    

    else 语句甚至没有必要;我只是为了完整性而包含它。

    【讨论】:

    • 我认为问题出在 mouseExited 方法上,因为它负责隐藏边框。顺便说一下,将侦听器提供给容器,而不是嵌套的 JTextField,因此当鼠标从任何嵌套的 JTextField 移动到容器外太快时,它不会触发:(
    • 在这种情况下,您需要做更多的繁重工作;在JTextField 上也放置一个MouseListener。退出场地时,if instanceof MyContainer do nothingelse remove border(因为我们假设您已经从 JTextField 直接走到外面。
    • 它可以工作,但我应该检查它是否是 jTextField 容器对象,否则如果我移动到另一个容器它无法隐藏它,对吗?
    • 好吧,看起来您已经找到了答案,但您并不总是需要检查它是否为JTextField,如果不是MyContainer,那么它将始终是JTextField 根据你的代码:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    • 2015-06-18
    相关资源
    最近更新 更多