we are currently working on fixes for a project that has to be finished next week, so we are kinda running out of time (don't worry, all I want to say is that we do not have the time to toss away all our code and start again fresh...).
We have a JPanel
(="page") with a bunch of other JPanels
(which act as nodes of a graph) on it. The user can connect the nodes by either clicking on the first and then on the second node to connect or by dragging a line from one to another.
But the last one is not working as we expected:
If we drag the connection line out of the node where it was started (e.g. to the page or any other node), the mouseDragged
event we are using to create the line does not end on a mouseRelease
. It works just fine if I release the mouse over the node where I started to drag, but I cant create any connections with that.
To be able to draw the connection to the page, we are dispatching the events until they reach the page where they will be handled.
Funny thing: everything works, except the fact that we have an endless chain of "mouse dragged" outputs if we put a System.out.println("mouse dragged");
in the code of mouseDragged()
.
Connecting itself works to.
So, my question is: how do I end a mouseDragged
event if the mouseReleased
occurs outside the component where the mouseDragged
initially started?
Is there a way to abort the mouseDragged
event?
Is it possible/necessary to "fake" an interrupting mouseRelease
event?
Hope there is a solution that will not make cook more coffee....
Greetings, Flo
EDIT: ok, got some code for you:
Interface implemented by the nodes and the page, makes things easier:
import java.awt.event.MouseEvent;
/**
* Interface which can be used together with MouseEventListenerAdapter to
* easily receive mouse events.
*
* @author flo
*/
public interface MouseEventsInterface {
/**
* Called when a mouse clicked event is received.
*
* @param e Triggered mouse event.
*/
void onMouseClicked(MouseEvent e);
/**
* Called when a mouse dragged event is received.
*
* @param e Triggered mouse event.
*/
void onMouseDragged(MouseEvent e);
[and so on...]
/**
* Called when a mouse released event is received.
*
* @param e Triggered mouse event.
*/
void onMouseReleased(MouseEvent e);
}
The Adapter to the events
/**
* Class which forwards mouse events to a MouseEventsInterface which have
* originally been targeted to a MouseInputAdapter.
*
* @author flo
*
* @param <M> The interface to which events are sent.
*/
public class MouseEventListenerAdapter<M extends MouseEventsInterface> extends MouseInputAdapter {
/**
* Interface which receives the events which are forwarded by this class.
*/
private M mei;
/**
* Creates an adapter which forwards all events to the MouseEventsInterface.
*
* @param mei The receiver of the forwarded events.
*/
public MouseEventListenerAdapter(final M mei) {
this.mei = mei;
}
@Override
public final void mousePressed(final MouseEvent e) {
this.mei.onMousePressed(e);
}
@Override
public final void mouseClicked(final MouseEvent e) {
this.mei.onMouseClicked(e);
}
@Override
public final void mouseDragged(final MouseEvent e) {
this.mei.onMouseDragged(e);
}
@Override
public final void mouseMoved(final MouseEvent e) {
this.mei.onMouseMoved(e);
}
@Override
public final void mouseReleased(final MouseEvent e) {
this.mei.onMouseReleased(e);
}
/**
* Returns the receiver of the forwarded {@link MouseEvent MouseEvents}.
* @return the receiver of the forwarded {@link MouseEvent MouseEvents}.
*/
protected final M getEventReceiver() {
return this.mei;
}
}
how we are dispatching the events, the first part is used if the event comes from another panel inside the node. The NodeConnectorMouseEvent is a regular MouseEvent with the ability to store all the components it has been dispachted from...
/**
* Dispatch mouse event.
*
* @param e the e
*/
private void dispatchMouseEvent(final MouseEvent e) {
if (e instanceof NodeConnectorMouseEvent) {
((NodeConnectorMouseEvent) e).addDispatchingComponent(this);
} else {
// f.e. moved over IOPort, PortPanel
e.setSource(this);
}
this.getParent().dispatchEvent(e);
}
some of the page's code:
@Override
public final void onMouseDragged(final MouseEvent e) {
System.out.println("Mouse: dragged");
if (isDragGestureActive) {
if (helperConnection != null && e instanceof NodeConnectorMouseEvent) {
NodeConnectorMouseEvent evt = (NodeConnectorMouseEvent) e;
if (containsIoPort(evt) != null && weAreDragging) {
Point absPosition = calcAbsolutePosition(evt);
// Discard drag events that would jump farther than 15 pixels,
//but only if we actually weren't dragging
if (weAreDragging
&& (Math.abs(absPosition.x - lastDragPosition.x) < 15
&& Math.abs(absPosition.y - lastDragPosition.y) < 15)) {
updateHelperConnection(absPosition);
}
lastDragPosition = absPosition;
}
} else if (e.getSource() instanceof EditorNode) {
moveSelectedNodes((EditorNode) e.getSource(), e.getX() - grabPosition.x, e.getY() - grabPosition.y);
} else {
return;
}
} else {
return;
}
}
@Override
public final void onMouseReleased(final MouseEvent e) {
System.out.println("Mouse: released");
if (e instanceof NodeConnectorMouseEvent) {
NodeConnectorMouseEvent evt = (NodeConnectorMouseEvent) e;
IOPort port = containsIoPort(evt);
if (port != null) {
weAreDragging = false;
lastDragPosition = new Point(0, 0);
onPortSelected(port);
}
} else if (e.getSource() instanceof EditorNode) {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
} else {
finishHelperConnection(null);
}
isDragGestureActive = false;
}
There is a lot more than that but I guess that was the interesting part. Thanks for your help!