In a fairly complicated codebase, there is functionality both to
(a) drag objects places, implemented with DragGestureRecognizer,
(b) and the ability to drag boxes around things to select them, implemented via e.g. mousePressed() listeners.
Normally they behave "correctly".
However there are some objects which are marked immovable, and when the user begins a mouse gesture on top of one of them, the DragGestureRecognizer is finding it, and apparently consuming the mouse event.
What I'd like to be able to do is e.g. add something to my DragGestureRecognizer to say "oh look, we found an immovable object, let's not have this be a drag after all", and allow the dragging-a-box-around-things to take control.
I realize I'm not providing code because there is way too much to provide, but short of disabling the DragGestureRecognizer entirely (bad), I haven't found a way to get it to (selectively) turn loose of mouse events. Any help much appreciated!
Related
I'm developing a plugin for IntelliJ IDEA, which obviously uses Swing.
For a feature I have introduced I'd like to stop a JPopupMenu which uses JCheckBoxMenuItems from losing focus and closing.
You can see it in action.
I've debugged the code, but I couldn't figure out how to do it, also being I'm not that into Swing.
Could you maybe point me to useful listeners/blocks of code/ways to prevent this?
If you want to see code, the IntelliJ classes are
ActionPopupMenuImpl.MyMenu
ActionMenuItem
Edit: a better way need to be found as the uiRefreshed event isn't always called at the right time.
Just coordinate your code in a good way ;)
The Swing mechanism in IDEA is too complicated, and maybe it's better to not touch it. Just know that the mouse events are handled by a special listener and then redirected to Component(s).
That said, having an hold on the menu ActionButton. You can listen for the Lookup's uiRefreshed event and programmatically:
myMenuButton.click()
That's all.
You need to call it after the UI has been refreshed because the LookupUi might have changed in dimension or location.
I am looking for a reliable way to be informed when the mouse moves and when the component beneath the mouse moves. While the first part can be rather easily implemented by using a MouseMotionListener, I am currently struggling with the second part.
Right now I have these two ideas:
1. Listen for all relevant changes
This one seems to be rather tough, so far I have
ComponentListener: When the component is moved
AncestorListener: When the ancestor is moved
MouseMotionListener: When the mouse is moved
And when a JScrollPane is used:
ChangeListener: When the view changes
Pros
Only triggers event based.
Cons
Breaks when JScrollPanes are used and you are not aware of it.
Additionally for my specific usecase I want to implement this hover behavior for a JEditorPane and the text layout could change. As described in the comments, for example changing text orientation of a text/rtf editor pane by pressing Ctrl + Shift + O.
2. Regularly check position and inform components
Regularly get the mouse position and inform the child component containing this position about it.
Pros
Catches all situations.
Cons
Always triggers, even if no change happened.
Is not immediate.
The component lookup is maybe rather expensive, especially with many nested components; I am currently using Container#findComponentAt but have not done any tests. (But maybe only as expensive as the lookup for MouseMotionListeners.)
Do you have other solution ideas, additions or changes to the ideas above?
I'd like to know what object a swing MouseMotionEvent (or MouseReleased) ends in. The problem is that both the MousePressed and MouseReleased events go to the object that was under the "press", not the release.
Here's a contrived example that may explain better:
The user sees a screen with some balls and some baskets and is told to drag a ball to a basket. Each ball represents some entity in the application space and each basket represents some action to take in the application space. From the Swing point of view, the balls and baskets are implemented separately as highly-overridden JButtons. On mousePressed the ball stores its identity in a known place. I'd like mouseReleased to be caught by a MouseListener in the basket which checks up the balls identity in the known place and then goes off into program logic and do the task represented by that basket.
But as I understand Swing (actually the AWT) the mouseReleased event goes to the component that contained the mousePressed event (ie the ball). Other than looking at X and Y (which seems an atrocious kludge) how do I figure out which basket the mouseReleased happened in? (If the mouseRelease happened outside of any basket, I'll need to take some sort of default reset action. Than can be done by a mouseEvent handler in the underlying JPanel).
(Please don't tell me this is a poor interface. The example I've given is not real. It abstracts out the problem I have in a way that I think is easy to visualize and understand.)
If the mouseRelease happened outside of any basket, I'll need to take some sort of default reset action -
Use the Drag and Drop API and then you will only be able to drop on components that support your drop.
Other than looking at X and Y (which seems an atrocious kludge)
Why? The event doesn't have the information so you need to get it somehow. So if you don't want to use the DnD API then you need to do this yourself.
There are methods in the API to help you do this:
Window window = SwingUtilities.windowForComponent( e.getComponent() );
Point dropPoint = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), window);
Component dropComponent = SwingUtilities.getDeepestComponentAt(window, dropPoint.x, dropPoint.y);
I've had this problem repeatedly over the years with AWT and Swing based interfaces: some mouse clicks events do not trigger mouseClicked in a MouseListener because the mouse moved at least one pixel during the click (which is most clicks with some mice). This is interpreted as a drag operation instead.
Is there a way to tell AWT/Swing to be a bit more permissive in its definition of a click?
Manually implementing a workaround is quite cumbersome if you want a full solution (if your components must also handle drag operations for instance):
Adding a unique MouseListener and MouseMotionListener to every component
Doing some sort of calculation of a click in mouseMoved, mouseDragged and mouseReleased (which requires measuring time elapsed, distance traveled...)
Forwarding the "fixed" mouse events to a new mouse input interface implemented by the components
There's got to be a better way! I'm hoping for a global setting but I just can't find one...
Related posts
https://stackoverflow.com/questions/20493509/drag-threshold-for-some-components-too-low
Making a component less sensitive to Dragging in Swing
Try setting the sensitivity of the D&D using:
System.setProperty("awt.dnd.drag.threshold", "5");
Note: this is only honored by List, Table, Text and Tree components!
See usages of javax.swing.plaf.basic.DragRecognitionSupport#mouseDragged() method.
I am already familiar with JButtons, JLabels and such, but I want to start making a game a very "colorful" menu. Is there a way to do this using Canvas (like adding a mouse listener and make some buttons in PhotoShop and detect if the mouse hovers over and clicks the button), or is there a better way?
Since you're already familiar with JButtons, you may find it easier (and more practical) simply to extend the existing JButton and modify its appearance, so that it looks like an image rather than the traditional grey button.
Amongst other things, it means you get all the standard button behaviour for free, including special cases, and in exchange all you have to do is override a couple of methods.
Have a read through the accepted answer for the following question, which explains pretty much exactly how to do that:
Creating a custom button in Java