Reputation: 4250
I have a JScrollPane
that can set its viewportView to a range of different panels. I want to get the JScrollPane component whenever any other component in its viewport is clicked. If I add a MouseListener
to the JScrollPane, it receives my mouse events when I click directly on the border of the pane, but not when I click on the components.
What's the right way to go about adding listeners and ultimately finding the enclosing scrollPane? I won't necessarily know ahead of time all the components on the panel that I show in the viewport - just that they'll be on some subclass of 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; }
}
In this example, I get mouse enter and exit events, but I can only get the mouse clicked event by clicking on the border around the text area. Even if I change the TestPane class to add listeners to its viewportView panel, I can't tell what's going on in the 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; }
}
I won't have any way of knowing what's on the JPanel, though, so I can't manually add listeners any deeper.
Upvotes: 2
Views: 5557
Reputation: 285450
Another possible way is to use an AWTEventListener, and then bubble up the parent tree to see if your component of interest has been pressed or holds a child that has been pressed. For example:
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;
}
}
Note: Please see this question and StanislovL's and mkorbel's answers for more on this.
Upvotes: 4
Reputation: 347332
The problem your going to have is if the panels contain content the also have mouse listeners, you will never be notified of those events (mouse events tend to be consumed by those higher in the chain)
You could use addNotify, simular to the way that the JTable works. You would then walk the parent chain until you could the component you wanted.
This of course assumes that you don't have your heart set on using the mouse listener...
Upvotes: 0
Reputation: 28707
You should add the mouse listener to the JScrollPane's view instead of to the scroll pane itself, since the scroll pane consists of only corners and scroll bars.
yourJScrollPane.getViewport().getView().addMouseListener(yourMouseListener);
This code segment will add your mouse listener to the JScrollPane's one viewport component.
Upvotes: 1