我们目前正在为一个必须在下周完成的项目进行修复,因此我们有点用光了(别担心,我要说的是,我们没有时间扔掉所有代码然后重新开始...)。
我们有一个JPanel
(=“ page”),上面还有一堆其他JPanels
(用作图的节点)。用户可以通过在第一个节点上单击然后在第二个节点上单击来连接或通过将一条线从一条线拖到另一条来连接节点。
但是最后一个没有按我们预期的那样工作:
如果我们将连接线拖出连接的起点(例如,拖到页面或其他节点),则用于创建连接线的mouseDragged
事件不会在mouseRelease
处结束。如果我将鼠标放到开始拖动的节点上,它会很好地工作,但无法与此建立任何连接。
为了能够绘制到页面的连接,我们正在调度事件,直到事件到达将要处理它们的页面为止。
有趣的是:一切正常,除了如果我们在System.out.println("mouse dragged");
的代码中放入mouseDragged()
,就会有无尽的“鼠标拖动”输出链。
连接本身即可。
因此,我的问题是:如果mouseDragged
发生在mouseReleased
最初启动的组件之外,如何结束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;
}
还有很多,但我想那是有趣的部分。
谢谢你的帮助!
最佳答案
我不确定我是否理解您的方法,但是请注意两点:
您可以consume()
“事件,以使源事件不会以默认方式对其进行处理”。
您可以push()
自己的EventQueue
并覆盖dispatchEvent()
来修改任何事件到其最终目的地的过程。有一个相关的示例here,而Global Event Dispatching是一个很好的指南。
附录:尽管不适用于眼前的问题,但还有其他方法可以选择多个节点:GraphPanel
使用鼠标拖动或Shift键单击选择多个选项,并使用右键单击查看上下文菜单。JGraph
使用shift-click进行多个选择; com.mxgraph.examples.swing.GraphEditor
是一个示例。
此example建议使用JInternalFrame
的方式。