2

I had a different problem first, so I made this post: Java JPanel mouse listener doesn't work over its components

The answers led me to arrive at a java GlassPane. I saw the other posts on SO about this and they all point to this article: http://weblogs.java.net/blog/alexfromsun/archive/2006/09/a_wellbehaved_g.html.

I used the example from the article (FinalGlassPane.java) and set it up exactly as in the test app:

GlassPane glass = new GlassPane(this);
getRootPane().setGlassPane(glass);
GestureListener gl = new GestureListener();
glass.addMouseMotionListener(gl);
glass.addMouseListener(gl);
glass.setVisible(true);
if (glass instanceof AWTEventListener) {
    AWTEventListener al = (AWTEventListener) glass;
    Toolkit.getDefaultToolkit().addAWTEventListener(al,
            AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
}

But I still have the same problem, the glass prevents me from being able to click any buttons (JButton) below it.

If you've been kind enough to read my initial SO question and think glassPane is not for me, please post me an alternative solution, otherwise please tell me why this isn't working.

Thanks in advance.

EDIT: IT WORKS but stops working when I add my own MouseListener

Notice in my code I was adding my own GestureListener, I can't add my own MouseListener to this implementation - that's what makes it not work. I took those lines off and the glass pane is now working correctly.

There is this notice in the code (FinalGlassPane.java) regarding MouseListener which I don't really understand, so my new question is how can I add my own MouseListener to this glass pane?

/**
 * If someone adds a mouseListener to the GlassPane or set a new cursor
 * we expect that he knows what he is doing
 * and return the super.contains(x, y)
 * otherwise we return false to respect the cursors
 * for the underneath components
 */
@Override
public boolean contains(int x, int y) {
    if (getMouseListeners().length == 0 && getMouseMotionListeners().length == 0
            && getMouseWheelListeners().length == 0
            && getCursor() == Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)) {
        return false;
    }
    return super.contains(x, y);
}

ADDITIONAL INFO:

If I always return false in the contains(int, int) method the buttons always work, but my MouseListener on the GlassPane doesn't. If I always return "super.contains(x,y)" then the opposite happens: MouseListener on the GlassPane works but I can't click any components underneath.

FINAL EDIT So I came to the conclusion that I can't (or don't) have a way (with Java 6) to allow my Application to have 2 layers which can receive MouseListener events (mousePressed, mouseReleased) at the same time. In the end I used the solution on my original question, which was to create a custom JButton and have that add the MouseListener to each instance.

Community
  • 1
  • 1
Ozzy
  • 8,244
  • 7
  • 55
  • 95
  • Can you abandan the glass(pain) idea add a master listener to all of the buttons? Would that case problems for your application? – Java42 Mar 22 '12 at 00:31
  • Actually in my application it is, because the buttons (grids of buttons) are generated from XML files OR sometimes generated from user objects. It would be a major pain to have to add the listener to each and every button, and i'm not even sure my listener would function correctly. – Ozzy Mar 22 '12 at 00:35
  • Yes. But 1st, How do you feel about using a custom button component in place of the swing JButton? – Java42 Mar 22 '12 at 00:57
  • I'll post the custom JButton on your other question. – Java42 Mar 22 '12 at 01:15
  • @ChuckFricano Oh That wouldn't be a problem at all because I'm already using my own custom JButton. BTW please check the editted question, because the clicks are now working through the glass panel (it was a stupid error on my behalf - sorry). – Ozzy Mar 22 '12 at 01:17

2 Answers2

2

not clear from your both questions, if you you really needed convertXxx or getXxx methods from SwingUtilities

1) you can put JLabel (dispatch mouse events) to the GlassPane, this JLabel could be placed / covering whole available Rectangle from JFrame, or only required Bounds

2) you can put JLabel (dispatch mouse events) to the JViewport, this JLabel could be placed / covering whole available Rectangle from JScrollPane / JViewport, or only required Bounds

3) you can use JLayeredPane (max 6 layers)

4) you can use JLayer (Java7) based on JXLayer (for Java6 and maybe better choice)

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • So I could've just used a JLayeredPane instead of a JPanel as my GlassPane and that would've done the job? @mKorbel – Ozzy Mar 22 '12 at 01:35
  • I don't know what do you really needed, and whats really your job is :-), please not attack to your person ---> I read there tons of wide question, without based on [SSCCE](http://sscce.org/), where reall answers was too far from question, my additional question, you want to e#consume() mouse events (GlassPane doesn't protect against KeyEvents), or you can re_distribute event, or ??? – mKorbel Mar 22 '12 at 01:47
  • I'm trying to make something for touch-screen PC system, but like android/iphone so it has Gesture feature. I made my GestureListener (you can see it in my answer here: http://stackoverflow.com/questions/6000408/java-swing-element-transitions/9811602#9811602) so I wanted to make a way to have a gesture-layer on top of my application frame, but allow me to use all the JButtons and other components as usual underneath. Whatever way is best I don't know, I'm still a newbie. Thanks for your help btw. And I think i'm already redistributing events (using Alex from Suns class) – Ozzy Mar 22 '12 at 01:54
  • @user1031312 ahaaaa do you meaning (maybe stupid example from Android phones) nice animations during unlocking locked phone ??? – mKorbel Mar 22 '12 at 02:04
  • Yes! And in android/iphone menu another example: slide-left/right to show next/prev menu. But Animation is not my question, animation is my **purpose** for this question. For animation I need a layer to read touch-input (touch gestures), so I used a GlassPane. @mKorbel – Ozzy Mar 22 '12 at 02:10
  • @user1031312 no this is about JLayer (JXLayer) or prehistoric LayeredPane, those containers JComponents are about AbsoluteLayout or setBounds, but I really don't know how supporting these Objects dragging on the screen (flicekring of contents), but [never ever hands up](http://tips4java.wordpress.com/?s=ComponentMover) – mKorbel Mar 22 '12 at 02:20
  • Oh I saw the link, no, I don't need to drag the components I will just use a JScrollPane and scroll to view the next JPanel. So I just need to make a JLayer to have the MouseListener on the top layer and the buttons underneath? I'm reading up about JLayer now... @mKorbel – Ozzy Mar 22 '12 at 02:48
  • @user1031312 JPanels inside JScrollPane doesn't supporting natural scrolling in compare with JPanel added to the JTable / JList, carefully with that :-) – mKorbel Mar 22 '12 at 02:52
  • @user1031312 don't use JList use JTable, wait second – mKorbel Mar 22 '12 at 03:22
  • haha okay... I'll just try different things and see which works best. – Ozzy Mar 22 '12 at 03:36
  • @user1031312 I checked one commercial code for foodstuffs, most easiest and confortable way could be CardLayout with MouseMotionListener, to determine mouse moved from Point to Point in shorh period, checked by Swing Timer, then output will be switch betweens cards, – mKorbel Mar 22 '12 at 03:44
  • Yes but MouseMotionListener doesn't clash with GlassPane - the MouseListener clashes with GlassPane. To determine a drag, we should know that the mouse button was pressed (mousePressed). I had the same problem with the JLayeredPane: only one layer can receive MouseListener events at one time. In the end I went with the answer in my original question: Use a custom JButton which automatically adds the Listener to each instance. Thanks for all your kind help. – Ozzy Mar 22 '12 at 15:18
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/9207/discussion-between-user1031312-and-mkorbel) – Ozzy Mar 22 '12 at 18:06
0

See the "How to Use Root Panes", in the Java Tutorials, search for the word 'redispatches' (about a page down), this has an example for something similar to what you're trying to achieve with checkboxes:

http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html

In short you need to use SwingUtilities.getDeepestComponentAt(..) and Component.dispatchEvent(..) while translating the location of the mouse cursor.

Chris White
  • 29,949
  • 4
  • 71
  • 93
  • Thanks for your answer. The problem with that method is that the component needs to be passed into the glass pane (via the constructor) - I can't do that. To make matters worse, the glass pane then adds a special listener to that component. If I wanted to add individual listeners, I would have done it without a glass pane. @ChrisWhite – Ozzy Mar 22 '12 at 00:48
  • Ok, the the article didn't exactly solve your problem, but it was the basis, which i've kindly expanded for you on pastebin: http://pastebin.com/YWHFX1qi – Chris White Mar 22 '12 at 10:44
  • Oh that was very kind of you, thank you. Actually, adding a MouseMotionListener wasn't a problem with the glass pane; the problem was when I added my own MouseListener to get the mousePressed and mouseReleased events. If you see the 'additional info' I added to this question, its to do with this contains(x, y) method. I can either set it to listen to the components underneath, or I can set it to listen to the glassPane by changing the return value. That's why I've finally decided to go with the answer in my original question - a custom JButton that auto-adds the Listener to each instance. – Ozzy Mar 22 '12 at 15:15