将事件转发到所有组件JAVA

我不知道如何解决这个问题。 我正在开发一个图形编辑器,可以绘制弧线(线)。 我手动将弧组件的大小设置为1000×1000,因此我不必在拖动此弧时更改它。 然后我在这个组件中绘制所需尺寸的弧。 每个弧组件都安装了鼠标侦听器。 问题是,只有最上面的弧组件才能获得鼠标消息。 此外,我在JPane本身上安装了一个鼠标点击监听器,但最上层组件上的鼠标点击监听器只是获取所有事件……有点难以描述这个问题,所以我将为您提供简单的图像

在此处输入图像描述

所以第一个解决方案是以某种方式将收到的消息转发给下面的组件,但是我不知道该怎么做,所以你有什么想法吗?

第二个解决方案是,不是为弧对象设置常量尺寸,而是以某种方式旋转该弧将成为的矩形,我的意思是这样。 在此处输入图像描述

但是,仍然存在重叠问题。

那么,您有什么想法如何解决这个问题? 或者如果您有任何其他想法,如何解决这个问题,我很高兴,我只需要正确的弧线对鼠标点击做出反应。

我不认为我的代码会以某种方式帮助,但在这里它是

arcObject.setSize(1000, 1000); // ! 

然后,在这个组件中我画一个弧

 toX = o2.x - 24 * Math.cos(theta); toY = o2.y - 24 * Math.sin(theta); g2.draw(new Line2D.Double(toX, toY, o1.x, o1.y)); 

你的意思是将MouseEvents从一个JComponent重定向到另一个JComponent吗?

在此处输入图像描述

 import javax.swing.*; import java.awt.event.*; import java.awt.Graphics; import java.awt.Color; import java.awt.Component; public class SSCCE { private JFrame componentsFrame = new JFrame(); private JFrame remoteFrame = new JFrame(); private int lastMouseX, lastMouseY; final JPanel panel = new JPanel(); public SSCCE() { panel.add(new JButton("A Button")); panel.add(new JComboBox(new String[]{"A", "Combo", "Box"})); panel.add(new JSlider()); panel.add(new JList(new String[]{"A", "List"})); panel.add(new JCheckBox("Check Box")); componentsFrame.add(panel); componentsFrame.setGlassPane(new JPanel() { private static final long serialVersionUID = 1L; @Override public void paintComponent(Graphics g) { g.setColor(Color.red); g.drawLine(lastMouseX - 8, lastMouseY, lastMouseX + 8, lastMouseY); g.drawLine(lastMouseX, lastMouseY - 8, lastMouseX, lastMouseY + 8); } @Override public boolean isOpaque() { return false; } @Override public boolean isVisible() { return true; } }); componentsFrame.setEnabled(false); componentsFrame.pack(); componentsFrame.setVisible(true); // MouseAdapter mouseImpl = new MouseAdapter() { private Component lastPressed; @Override public void mousePressed(MouseEvent e) { redirectMouseEvent(e); } @Override public void mouseReleased(MouseEvent e) { redirectMouseEvent(e); } @Override public void mouseClicked(MouseEvent e) { redirectMouseEvent(e); } @Override public void mouseMoved(MouseEvent e) { redirectMouseEvent(e); } @Override public void mouseDragged(MouseEvent e) { redirectMouseEvent(e); } private void redirectMouseEvent(MouseEvent e) { Component redirectTo = SwingUtilities.getDeepestComponentAt(panel, e.getX(), e.getY()); if (e.getID() == MouseEvent.MOUSE_PRESSED) { lastPressed = redirectTo; } else if (e.getID() == MouseEvent.MOUSE_DRAGGED || e.getID() == MouseEvent.MOUSE_RELEASED) { redirectTo = lastPressed; } if (redirectTo != null) { lastMouseX = e.getX(); lastMouseY = e.getY(); panel.repaint(); //this line is just to update the glass pane e = SwingUtilities.convertMouseEvent(panel, e, redirectTo); java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e); } } }; remoteFrame.getContentPane().addMouseListener(mouseImpl); remoteFrame.getContentPane().addMouseMotionListener(mouseImpl); remoteFrame.setSize(componentsFrame.getSize()); remoteFrame.setLocation(0, componentsFrame.getY() + componentsFrame.getHeight()); remoteFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); remoteFrame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { SSCCE sSCCE = new SSCCE(); } }); } } 

您可以调整GraphPanel显示的方法。 虽然List的所选实现具有固定顺序,但是不同的实现可以允许诸如Move ForwardMove BackwardGroup

我这样解决了:

  1. 将所有创建的弧保存到List
  2. 单击鼠标时,循环遍历所有弧
  3. 创建新的Line2D对象,并将弧的参数保存在列表中,如下所示:

    Line2D line = new Line2D.Double(…)

  4. 检查这个条件

    if(line.ptLineDist(x,y)<3){... //我们点击了这一行,做了些什么

    }

我尝试了两种方法将事件转发到几个组件。 第一种方法是将事件从GlassPane重新分配到其GlassPane的所有组件。 第二种方法是使用全局偶数监听器AWTEventListener

这是第一种方式的代码。 请注意,如果您的GlassPane具有其他大小而不是ContentPane ,则需要转换鼠标光标的坐标(我不知道但是我将convertPoint(...)方法convertPoint(...)为相关)。

 import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; public class Test extends JFrame { public Test() { super(); JButton testBtn = new JButton("Test"); testBtn.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { System.out.println("Button's MouseEvent"); } }); add(testBtn, BorderLayout.SOUTH); ControlPanel control = new ControlPanel(getContentPane()); setGlassPane(control); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(200, 200); setVisible(true); control.setVisible(true); } private class ControlPanel extends JComponent { private Container underControl; public ControlPanel(Container underControl) { this.underControl = underControl; // Instead settig some listeners. // If any listeners doesn't set, any events will not process enableEvents(MouseEvent.MOUSE_EVENT_MASK); setOpaque(false); } @Override public void processMouseEvent(MouseEvent e) { // do something redispatchMouseEvent(e); } private void redispatchMouseEvent(MouseEvent e) { System.out.println("redispatchMouseEvent()"); Component[] components = underControl.getComponents(); for(Component c : components) { if(c.getBounds().contains(e.getX(), e.getY())) { e = SwingUtilities.convertMouseEvent(underControl, e, c); java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e); } } } } public static void main(String[] args) { new Test(); } } 

这是第二种方式。

 import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.event.MouseInputAdapter; public class Test extends JFrame { public Test() { super(); JButton btn = new JButton("Test"); btn.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { System.out.println("JButton.onMouseClicked()"); } }); add(btn, "South"); long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK; Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener() { public void eventDispatched(AWTEvent e) { System.out.println(e.getID()); if(e.getID() == MouseEvent.MOUSE_DRAGGED) { System.out.println("Dragged"); } if(e.getSource() instanceof JButton) { System.out.println("Under the button"); } } }, eventMask ); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(200, 200); setVisible(true); } public static void main(String[] args) { new Test(); } }