Making a component less sensitive to Dragging in Swing - java

A JComponent of mine is firing a mouseDragged event too vigorously. When the user is trying to click, it interprets is as a drag even if the mouse has only moved 1 pixel.
How would I add a rule for a particular component that amounted to:
Do not consider it a drag event unless
the mouse has moved 10 pixels from the
point at which is was pressed down.
Note: I know it's not a system setting in my OS, since only events on that component suffer from this over sensitivity.
Thank you.

Previous answers combined together, with proper event type:
public class DragInsensitiveMouseClickListener implements MouseInputListener {
protected static final int MAX_CLICK_DISTANCE = 15;
private final MouseInputListener target;
public MouseEvent pressed;
public DragInsensitiveMouseClickListener(MouseInputListener target) {
this.target = target;
}
#Override
public final void mousePressed(MouseEvent e) {
pressed = e;
target.mousePressed(e);
}
private int getDragDistance(MouseEvent e) {
int distance = 0;
distance += Math.abs(pressed.getXOnScreen() - e.getXOnScreen());
distance += Math.abs(pressed.getYOnScreen() - e.getYOnScreen());
return distance;
}
#Override
public final void mouseReleased(MouseEvent e) {
target.mouseReleased(e);
if (pressed != null) {
if (getDragDistance(e) < MAX_CLICK_DISTANCE) {
MouseEvent clickEvent = new MouseEvent((Component) pressed.getSource(),
MouseEvent.MOUSE_CLICKED, e.getWhen(), pressed.getModifiers(),
pressed.getX(), pressed.getY(), pressed.getXOnScreen(), pressed.getYOnScreen(),
pressed.getClickCount(), pressed.isPopupTrigger(), pressed.getButton());
target.mouseClicked(clickEvent);
}
pressed = null;
}
}
#Override
public void mouseClicked(MouseEvent e) {
//do nothing, handled by pressed/released handlers
}
#Override
public void mouseEntered(MouseEvent e) {
target.mouseEntered(e);
}
#Override
public void mouseExited(MouseEvent e) {
target.mouseExited(e);
}
#Override
public void mouseDragged(MouseEvent e) {
if (pressed != null) {
if (getDragDistance(e) < MAX_CLICK_DISTANCE) return; //do not trigger drag yet (distance is in "click" perimeter
pressed = null;
}
target.mouseDragged(e);
}
#Override
public void mouseMoved(MouseEvent e) {
target.mouseMoved(e);
}
}

I've had to do exactly this before. Here's my mouse event processing code, cut down to just the bits relating to making drag require a few pixels before being treated as a drag.
public void mousePressed(int mod, Point loc) {
pressLocation=copyLocation(loc,pressLocation);
dragLocation=null;
}
public void mouseReleased(int mod, Point loc) {
if(pressLocation!=null && dragLocation!=null) {
// Mouse drag reverted to mouse click - not dragged far enough
// action for click
pressLocation=null;
}
else if(dragLocation!=null) {
// action for drag completed
}
else {
// do nothing
}
pressLocation=null;
dragLocation=null;
}
public void mouseDragged(int mod, Point loc) {
if(pressLocation!=null) { // initial drag actions following mouse press
dragLocation=pressLocation; // consider dragging to be from start point
if(Math.abs(loc.x-pressLocation.x)<dragMinimum && Math.abs(loc.y-pressLocation.y)<dragMinimum) {
return; // not dragged far enough to count as drag (yet)
}
// action drag from press location
pressLocation=null;
}
else {
// action drag from last drag location
dragLocation=copyLocation(loc,dragLocation);
}
}
And note, I also had problems with Java some JVM's generating click events after dragging, which I had to detect and suppress.

If I read your question correctly, you're tracking both click and mousedrag events. Can you track the coordinates upon mousedown, followed by a short computation in mousedrag to see if the mouse has moved your desired minimum numbers of pixels? Of course, you then also want to cancel/reset on mouseup or when the mouse is dragged outside the bounds of your JComponent.
Caveat: I haven't done this myself, but I think it's where I'd start if it were me.

Software Monkey's code seemed to be missing some code, so I wrote this solution:
navigationTree.addMouseListener(new DragInsensitiveMouseClickListener(10) {
#Override
public void mouseClicked(MouseEvent e) {
TreePath treePath = navigationTree.getPathForLocation(e.getX(), e.getY());
if(treePath != null) {
processChoice();
}
}
});
This will still fire the mouseClicked() event when the user produces at most 10 pixels of "drag travel".
The code for the click listener:
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class DragInsensitiveMouseClickListener extends MouseAdapter {
private final int allowedTravel;
public Point mouseDownPoint;
public DragInsensitiveMouseClickListener(int allowedTravel) {
this.allowedTravel = allowedTravel;
}
#Override
public void mousePressed(MouseEvent e) {
mouseDownPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
double horizontalTravel = Math.abs(mouseDownPoint.getX() - e.getX());
double verticalTravel = Math.abs(mouseDownPoint.getY() - e.getY());
if (horizontalTravel < allowedTravel && verticalTravel < allowedTravel) {
mouseClicked(e);
}
}
}

Related

OpenImaj - Using a MouseListener with JFrame

I'm attempting to add mouse listening capabilities to a JFrame that displays an MBFImage and the mouse events do absolutely nothing. I'm not sure if the events are not firing or if they are and not being caught because I am doing something wrong...
The image shows up in the JFrame just fine, however moving the mouse around over the image, clicking, moving, dragging, etc. does not result in any activity.
NOTE 1 I've discovered that if I add the mouselistener to a JPanel and then (in this specific order) draw the image and then add the the JPanel to the JFrame, that the mouse listener catches the events, but ONLY listens outside of the image. It draws a minimum size window which I need to resize. Any mouse movement over the image does not seem to fire / catch any events.
NOTE 2 If I add the panel to the JFrame and then draw the image, the window size is just fine, however the mouse listener no longer work.
Can anyone shed any light?
Here is the relevant portion of my code:
private JFrame displayImage(final MyAppImage image, final MyAppImage.DetectLevel level, String title) {
MBFImage mbfImg = image.drawDetections(level); //draws face detection boxes
JFrame imgFrame = new JFrame(title);
DisplayUtilities.display(mbfImg, imgFrame);
imgFrame.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("here");
if (level == MyAppImage.DetectLevel.filtered) {
if (image.checkPoints(e.getX(), e.getY(), level) != null) {
System.out.println("YES");
}
else {
System.out.println("NO!");
}
}
else {
System.out.println("Huh?");
}
}
#Override
public void mouseExited(MouseEvent e) {
}
});
imgFrame.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
System.out.println("hello");
}
#Override
public void mouseMoved(MouseEvent e) {
System.out.println("here");
if (level == MyAppImage.DetectLevel.filtered) {
if (image.checkPoints(e.getX(), e.getY(), level) != null) {
System.out.println("YES");
}
else {
System.out.println("NO!");
}
}
else {
System.out.println("Huh?");
}
}
});
return imgFrame;
}
Exactly what #MadProgrammer commented - when you call DisplayUtilities.display(mbfImg, imgFrame); it creates an ImageComponent inside your JFrame that is itself a MouseListener.
You should be able to add a MouseListener to the ImageComponent directly however.

Java - keyboard state after leaving window

The title might be a little misleading, didnt know how to put my problem short.
Basically what im doing is im using keyboardlistener to find out which keys are down and according to that im moving my game character.
The problem is, when you click out of the window, while holding down a key my listener doesnt register the keyReleased event.
I tried to fix it by using mouse listener and the mouseExited event, but that doesnt fix it all the time, sometimes it does sometimes it doesnt.
Heres my implementation:
Keyboard:
public void mouseLeftWindow()
{
for(int i =0;i<KEY_COUNT;i++)
{
keys[i] = false;
}
}
#Override
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if(keyCode>=0 && keyCode<KEY_COUNT)
{
keys[keyCode] = true;
}
}
#Override
public void keyReleased(KeyEvent e)
{
int keyCode = e.getKeyCode();
if(keyCode>=0 && keyCode<KEY_COUNT)
{
keys[keyCode] = false;
}
}
where keys[] is a boolean[] describing, which codes are pressed
mouse:
#Override
public void mouseExited(MouseEvent e)
{
mouseMoved(e);
keyboard.mouseLeftWindow();
}
Your program will listen for further key events even when your mouse exited the component. That means you set everything to false on exit but if a key is still pressed it will be set to true immediately again. I think you are looking for a FocusListener instead of a MouseListener.
addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
}
#Override
public void focusLost(FocusEvent e) {
keyboard.mouseLeftWindow();
}
});

Shape position wont redraw when dragged with mouse

I have a filled circle drawn on a canvas and I'm trying to get it to move based on a click and drag method with the mouse. I've managed to checked whether the mouse pointer is within the bounds of the circle, and when I drag the mouse, the variable storing the position of the circle updates as it should, but the circle itself is not redrawing as I'm dragging (the most it will do is flicker). My problem is at the end where I'm overriding mouseDragged().
getCanvas().addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent event)
{
super.mouseClicked(event);
Point mousePosition = event.getPoint();
if (_circle.getShape1().contains(mousePosition))
Main.debugLabel.setText("Clicked");
}
#Override
public void mouseReleased(MouseEvent event)
{
super.mouseReleased(event);
_circle.isDraggable = false;
Main.debugLabel.setText("Released");
}
#Override
public void mousePressed(MouseEvent event)
{
super.mousePressed(event);
int button = event.getModifiers();
if (button == InputEvent.BUTTON1_MASK)
{
_circle.isDraggable = true;
Main.debugLabel.setText("Pressed");
}
}
});
getCanvas().addMouseMotionListener(new MouseAdapter()
{
#Override
public void mouseDragged(MouseEvent event)
{
super.mouseDragged(event);
Point mousePosition = event.getPoint();
if (_circle.isDraggable)
{
_circle.posX = mousePosition.x;
_circle.posY = mousePosition.y;
Main.debugLabel.setText("Dragging " + _circle.posX);
getCanvas().repaint();
}
}
#Override
public void mouseMoved(MouseEvent event)
{
super.mouseMoved(event);
Point mousePosition = event.getPoint();
if (_circle.getShape1().contains(mousePosition))
Main.debugLabel.setText("Within Bounds");
else if (!_circle.getShape1().contains(mousePosition) && !_circle.isDraggable)
Main.debugLabel.setText("Out of Bounds");
}
});
As shown in this example, one approach is to maintain two Point instances. One holds the last mouse location; the other holds the desired target location; both are in in component-relative coordinates.
In mousePressed(),
Initialize the last mouse location.
Optionally, mark the target as selected.
Invoke repaint() to display the selected appearance.
In mouseDragged(),
Update the target location by the difference between the new and old mouse locations.
Update the last mouse location to the current mouse location.
Invoke repaint().

mouse pressed->drag->released. in java

Excuse me:
I just can't know how to link these successive operation?
Mouse pressed and then drag then release. If an user doesn't do this operation some action won't happen...
Should I add code as the is already pressed to distinguish that?
The constant MOUSE_MOVED doesn't work since Eclipse told me it doesn't know it although I find the parameter in mouse event api
I don't know what's going on... Please help!
Implement a MouseInputListener using a MouseInputAdapter subclass and handle the mousePressed, mouseDragged, and the mouseReleased events.
Take a look at this tutorial for examples.
Here is a simple class that encapsulates the drag detection:
public abstract static class MouseDragListener {
java.awt.Component component;
MouseEvent dragStart;
public MouseDragListener(java.awt.Component component) {
super();
this.component = component;
component.addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
dragStart = null;
}
public void mouseDragged(MouseEvent e) {
if (dragStart == null)
dragStart = e;
}
});
component.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if (dragStart != null) {
dragReleased(dragStart, e);
}
}
});
}
then to use:
new MouseDragListener(center){
void dragReleased(MouseEvent start,MouseEvent end){
// do something ...
}
}

How to change the mouse cursor in java?

I have a list of words inside the JList. Every time I point the mouse cursor at a word, I want the cursor to change into a hand cursor. Now my problem is how to do that?
Could someone help me with this problem?
Use a MouseMotionListener on your JList to detect when the mouse enters it and then call setCursor to convert it into a HAND_CURSOR.
Sample code:
final JList list = new JList(new String[] {"a","b","c"});
list.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseMoved(MouseEvent e) {
final int x = e.getX();
final int y = e.getY();
// only display a hand if the cursor is over the items
final Rectangle cellBounds = list.getCellBounds(0, list.getModel().getSize() - 1);
if (cellBounds != null && cellBounds.contains(x, y)) {
list.setCursor(new Cursor(Cursor.HAND_CURSOR));
} else {
list.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
#Override
public void mouseDragged(MouseEvent e) {
}
});
You probably want to look at the Component.setCursor method, and use it together with the Cursor.HAND constant.
You can also add MouseListener to the jList (or any ui component). Then implement the methods that mouseEntered, mouseExited
jList.addMouseListener(new MouseListener() {
#Override
public void mouseEntered(MouseEvent e) {
cw.list.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
#Override
public void mouseExited(MouseEvent e) {
cw.list.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});

Categories

Resources