在视口组件上使用JScrollPane鼠标侦听器

我有一个JScrollPane ,可以将其viewportView设置为一系列不同的面板。 我希望在单击其视口中的任何其他组件时获取JScrollPane组件。 如果我将一个MouseListener添加到JScrollPane,当我直接单击窗格的边框时,它会接收我的鼠标事件,但是当我单击组件时则不会。

添加监听器并最终找到封闭的scrollPane的正确方法是什么? 我不一定提前知道我在视口中显示的面板上的所有组件 – 只是它们将在JPanel的某个子类上。

 import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.event.MouseInputAdapter; import net.miginfocom.swing.MigLayout; public class TestScrollPane extends MouseInputAdapter{ public void mouseEntered(MouseEvent arg0) {System.out.println("Entered " + arg0.getComponent());} public void mouseExited(MouseEvent arg0) {System.out.println("Exited " + arg0.getComponent());} public void mousePressed(MouseEvent arg0) {System.out.println("Pressed " + arg0.getComponent());} public void mouseReleased(MouseEvent arg0) {System.out.println("Released " + arg0.getComponent());} public static void main(String[] args){ JFrame frame = new JFrame(); frame.setLayout(new MigLayout()); frame.setSize(400, 400); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); TestPane pane1 = new TestPane("Scroll Pane 1"); TestPane pane2 = new TestPane("Scroll Pane 2"); frame.add(pane1, "push,grow"); frame.add(pane2, "push, grow"); TestMouseListener listener = new TestMouseListener(); pane1.addMouseListener(listener); pane1.addMouseMotionListener(listener); pane2.addMouseListener(listener); pane2.addMouseMotionListener(listener); frame.setVisible(true); } } class TestPanel2 extends JPanel { String name; TestPanel2(String name){ this.name = name; setLayout(new MigLayout()); JTextArea area = new JTextArea(); area.append(name); add(area, "push, grow"); } public String toString(){ return name; } } class TestPane extends JScrollPane { String name; TestPane(String name){ this.name = name; TestPanel2 panel = new TestPanel2(name + " panel"); setViewportView(panel); } public String toString(){ return name; } } 

在这个例子中,我得到鼠标进入和退出事件,但我只能通过单击文本区域周围的边框来获取鼠标单击事件。 即使我更改了TestPane类以将侦听器添加到其viewportView面板,我也无法分辨textArea中发生了什么。

 class TestPane extends JScrollPane { String name; TestPane(String name){ this.name = name; TestPanel2 panel = new TestPanel2(name + " panel"); TestMouseListener listener = new TestMouseListener(); panel.addMouseListener(listener); panel.addMouseMotionListener(listener); setViewportView(panel); } public String toString(){ return name; } } 

但是,我无法知道JPanel上的内容,所以我无法更深入地手动添加监听器。

另一种可能的方法是使用AWTEventListener,然后冒泡父树以查看是否已按下您感兴趣的组件或保持已按下的子组件。 例如:

 import java.awt.AWTEvent; import java.awt.Component; import java.awt.FlowLayout; import java.awt.Toolkit; import java.awt.event.AWTEventListener; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.event.MouseInputAdapter; // import net.miginfocom.swing.MigLayout; public class TestScrollPane extends MouseInputAdapter { public void mouseEntered(MouseEvent arg0) { System.out.println("Entered " + arg0.getComponent()); } public void mouseExited(MouseEvent arg0) { System.out.println("Exited " + arg0.getComponent()); } public void mousePressed(MouseEvent arg0) { System.out.println("Pressed " + arg0.getComponent()); } public void mouseReleased(MouseEvent arg0) { System.out.println("Released " + arg0.getComponent()); } public static void main(String[] args) { JFrame frame = new JFrame(); // frame.setLayout(new MigLayout()); frame.getContentPane().setLayout(new FlowLayout()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); TestPane pane1 = new TestPane("Scroll Pane 1"); TestPane pane2 = new TestPane("Scroll Pane 2"); frame.add(pane1, "push,grow"); frame.add(pane2, "push, grow"); // !! TestMouseListener listener = new TestMouseListener(); TestScrollPane listener = new TestScrollPane(); pane1.addMouseListener(listener); pane1.addMouseMotionListener(listener); pane2.addMouseListener(listener); pane2.addMouseMotionListener(listener); frame.pack(); frame.setVisible(true); Toolkit.getDefaultToolkit().addAWTEventListener( listener.createAWTWindowListener(), AWTEvent.MOUSE_EVENT_MASK); } private AWTEventListener createAWTWindowListener() { AWTEventListener awt1 = new AWTEventListener() { @Override public void eventDispatched(AWTEvent e) { if (MouseEvent.MOUSE_PRESSED == e.getID()) { MouseEvent event = (MouseEvent) e; Component comp = event.getComponent(); if (comp != null) { String scrollPanelName = recursivelyCheckForScrollPanel(comp); if (scrollPanelName != null) { System.out.println("TestPane pressed. Name: " + scrollPanelName); } else { System.out.println("TestPane not pressed"); } } } } private String recursivelyCheckForScrollPanel(Component comp) { if (comp instanceof TestPane) { return comp.toString(); } else { comp = comp.getParent(); if (comp != null) { return recursivelyCheckForScrollPanel(comp); } } return null; } }; return awt1; } } class TestPanel2 extends JPanel { String name; TestPanel2(String name) { this.name = name; // setLayout(new MigLayout()); JTextArea area = new JTextArea(5, 20); area.append(name); add(area, "push, grow"); } public String toString() { return name; } } class TestPane extends JScrollPane { String name; TestPane(String name) { this.name = name; TestPanel2 panel = new TestPanel2(name + " panel"); setViewportView(panel); } public String toString() { return name; } } 

注意:请参阅此问题以及StanislovL和mkorbel的答案以获取更多相关信息。

您应该将鼠标侦听器添加到JScrollPane的视图而不是滚动窗格本身,因为滚动窗格仅包含角和滚动条。

 yourJScrollPane.getViewport().getView().addMouseListener(yourMouseListener); 

此代码段将您的鼠标侦听器添加到JScrollPane的一个视口组件中。

您将遇到的问题是,如果面板包含内容也有鼠标侦听器,您将永远不会收到有关这些事件的通知(鼠标事件往往被链中较高的人使用)

您可以使用addNotify,与JTable的工作方式类似。 然后,您将遍历父链,直到您可以使用所需的组件。

这当然假设你没有心脏使用鼠标监听器……