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 ...
}
}
Related
I want to create a JDialog where the text in the textfields is selected but only if the focus is gained from keyboard (TAB, CTRL+TAB). I have found several topics on this matter but had problems with implementing it.
Here is one which I was trying.
And my code:
public class Dialogg extends JDialog implements FocusListener, MouseListener {
private boolean focusFromMouse = false;
public Dialogg() {
JTextField tf1 = new JTextField("text1");
JTextField tf2 = new JTextField("text2");
tf1.addMouseListener(this);
tf2.addMouseListener(this);
tf1.addFocusListener(this);
tf2.addFocusListener(this);
}
#Override
public void focusGained(FocusEvent e) {
if (!focusFromMouse) {
JTextField tf = (JTextField) e.getComponent();
tf.selectAll();
focusFromMouse = true;
}
}
#Override
public void focusLost(FocusEvent e) {
focusFromMouse = false;
}
#Override
public void mouseClicked(MouseEvent e) {
focusFromMouse = true;
}
}
It does not work as intended, it does not matter what is focus source the text always highlights. When I run the code and follow it step by step it turns out that focusGained code happens before mouseClicked code so the flag is not reset when it should. Any hints?
EDIT:
As suggested by M. Prokhorov I have deleted less relevant (for the question) lines from the code.Thank you.
EDIT 2:
I am trying to wrap focus listener as suggested by camickr. It looks like this now:
tf1.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (!focusFromMouse){
tf1.selectAll();
focusFromMouse=true;
}
}
});
}
public void focusLost(FocusEvent evt){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
focusFromMouse=false;
}
});
}
});
public void mouseClicked(MouseEvent e) {
focusFromMouse=true;
I am printing line after each event to see the action order and still mouseClicked happens last. What am I doing wrong?
EDIT 3:
OK, I have found a solution which fulfils requirements of my simple Dialog.
I could not find a way of doing this with use of invokeLater or EventQueue. Vladislav's method works but as I understand it restricts the user to only use the keyboard.
I have used the initial approach but I have added an auxiliary variable and few conditions which allow to pass the flag "unharmed" trough Events that should not change the flag at given moment. It may not be subtle or universal but works for my app. Here is the code:
public void focusGained(FocusEvent e) {
if(!focusFromMouse){
if (higlight){
JTextField tf = (JTextField) e.getComponent();
tf.selectAll();
focusFromMouse=false;
}
}
}
public void focusLost(FocusEvent e) {
if (focusFromMouse){
higlight=false;
focusFromMouse=false;
}else{
higlight=true;
}
}
public void mousePressed(MouseEvent e) {
focusFromMouse=true;
}
At the first, by default, focus on JTextField is requested by mouse-press event, not by mouse-click.
So, this method:
public void mouseClicked(MouseEvent e) {
focusFromMouse = true;
}
is useless because the mouse-click event is triggered after the mouse-press event.
One way to solve your problem is to remove all native MouseListeners from JTextField:
...
for( MouseListener ml : tf1.getMouseListeners() ){
tf1.removeMouseListener(ml);
}
for( MouseMotionListener mml : tf1.getMouseMotionListeners() ){
tf1.removeMouseMotionListener(mml);
}
...
Another way is to handle all mouse events and consume those of them, which are triggered by JTextField:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if( event.getSource() == tf1 ){
((MouseEvent)event).consume();
}
}
}, AWTEvent.MOUSE_EVENT_MASK);
When I run the code and follow it step by step it turns out that focusGained code happens before mouseClicked
Wrap the code in the FocusListener in a SwingUtilities.invokeLater(). The will place the code on the end of the Event Dispatch Thread (EDT), so the code will run after the variable in the MouseListener has been set.
See Concurrency in Swing for more information about the EDT.
Edit:
Just noticed the other answer. You might be able to do something simpler. Istead of listener for mouseClicked, listen for mousePressed. A mouseClicked event is only generated AFTER the mouseReleased event, so by that time the FocusListener logic has already been executed, even when added to the end of the EDT.
Edit 2:
If the above doesn't work then you might be able to use the EventQueue.peek() method to see if a MouseEvent is on the queue. This might even be easier than worrying about using the invokeLater.
I am using an Icon with Java (Swing) JButton. Is it possible to change the icon when I take my mouse arrow over it?
I saw somewhere on Youtube that it is possible, but am unable to recall it.
You can take advantage of the JButton API which provides this kind of support.
Take a look at JButton#setRolloverIcon and JButton#setRolloverSelectedIcon
You will need to implement MouseListener like this:
public class YourClass extends JFrame implements MouseListener {
#Override
public void mouseEntered(MouseEvent e) { }
#Override
public void mouseExited(MouseEvent e) { }
#Override
public void mouseClicked(MouseEvent e) { }
#Override
public void mousePressed(MouseEvent e) { }
#Override
public void mouseReleased(MouseEvent e) { }
}
Add your function where needed.
You can override the mouseEntered() function by implementing a MouseListener and add the code to change the icon in that function.
If you're using an abstract button, you can just use setRolloverIcon() to set an image which will appear on rollOver.
The cells in my JTable become editable only on the second click. When I debugged I noticed that on the second click the mouse released event is not fired. I saw a lot of answers for this problem with create a setSingleClick(1)... but it doesn't to work. I think that if i can get that second mouseReleased event to get fire i might be able to make it work. Does anybody has any sugestions?
table.addMouseListener(new TableMouseListener()) ;
class TableMouseListener extends MouseAdapter{
public void mousePressed(MouseEvent e) {
System.out.println("mousePressed");
}
public void mouseClicked(MouseEvent e) {
System.out.println("mouseClicked");
}
public void mouseReleased(MouseEvent e) {
System.out.println("mouseReleased");
}
}
Try something like this:
container_table.addMouseListener(new MouseAdapter() {
public void mouseClicked (MouseEvent me) {
if (me.getClickCount() == 2) {
//Double clicked
}
}
});
This way, you know that the 'container_table' has been clicked twice, and then you can get the selected row, and make things with it.
Hope it helps.
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));
}
});
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);
}
}
}