【发布时间】:2012-02-26 00:57:55
【问题描述】:
我们目前正在修复一个必须在下周完成的项目,所以我们的时间已经不多了(别担心,我只想说我们没有时间折腾我们所有的代码,然后重新开始......)。
我们有一个 JPanel (="page") 和一堆其他的 JPanels (充当图的节点)。用户可以通过单击第一个节点然后单击第二个节点来连接节点,或者通过将一条线从一个节点拖到另一个节点来连接节点。
但是最后一个并没有像我们预期的那样工作:
如果我们将连接线拖出它开始的节点(例如,到页面或任何其他节点),我们用来创建连接线的mouseDragged 事件不会以mouseRelease 结束。如果我在开始拖动的节点上释放鼠标,它就可以正常工作,但我无法创建任何连接。
为了能够绘制到页面的连接,我们正在调度事件,直到它们到达将要处理它们的页面。
有趣的是:一切正常,除了如果我们在mouseDragged() 的代码中添加System.out.println("mouse dragged");,我们就会有无穷无尽的“鼠标拖动”输出链。
连接本身起作用。
所以,我的问题是:如果mouseReleased 发生在mouseDragged 最初开始的组件之外,我该如何结束mouseDragged 事件?
有没有办法中止mouseDragged 事件?
是否有可能/有必要“伪造”一个中断的mouseRelease 事件?
希望有一个解决方案,不会让煮更多的咖啡......
您好, 弗洛尔
编辑: 好的,给你一些代码:
节点和页面实现的接口,让事情变得更简单:
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);
}
事件的适配器
/**
* 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;
}
}
我们如何调度事件,如果事件来自节点内的另一个面板,则使用第一部分。 NodeConnectorMouseEvent 是一个常规的 MouseEvent,它能够存储所有发送它的组件...
/**
* 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);
}
部分页面代码:
@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;
}
还有很多,但我想这是有趣的部分。 感谢您的帮助!
【问题讨论】:
-
它应该按预期结束,无需特殊代码。您确定要同时处理 MouseMotionListener 和 MouseListener 事件吗?没有代码很难说更多......
-
如果允许,您可以考虑使用 JLayer (jdk7) 或 JXLayer (jdk6) 来装饰节点的父节点 - 您将在自定义 LayerUI 中实现所有鼠标跟踪和线条绘制,即'会大大简化你的逻辑。
标签: java swing drag-and-drop release mouseevent