java: end mouseDragged при отпускании мыши вне исходного компонента - PullRequest
1 голос
/ 26 февраля 2012

В настоящее время мы работаем над исправлениями для проекта, который должен быть завершен на следующей неделе, поэтому у нас как бы заканчивается время (не волнуйтесь, все, что я хочу сказать, это то, что у нас нет времени отбросить весь наш код и начать заново заново ...).

У нас есть JPanel (= "страница") с кучей других JPanels (которые действуют как узлы графа) на нем. Пользователь может соединить узлы, щелкнув по первому, а затем по второму узлу для соединения, или перетащив линию из одного в другой. Но последний не работает, как мы ожидали:

Если мы перетащим линию соединения из узла, где она была запущена (например, на страницу или любой другой узел), событие mouseDragged, которое мы используем для создания линии, не заканчивается на mouseRelease. Это прекрасно работает, если я отпущу мышь над узлом, где я начал перетаскивать, но я не могу создать какие-либо связи с этим.

Чтобы установить связь со страницей, мы отправляем события до тех пор, пока они не достигнут страницы, на которой они будут обрабатываться.

Забавная вещь: все работает, за исключением того, что у нас есть бесконечная цепочка «перетаскиваемых мышью» выходов, если мы вставим System.out.println("mouse dragged"); в код mouseDragged(). Само соединение работает с.

Итак, мой вопрос: как мне завершить событие mouseDragged, если mouseReleased происходит за пределами компонента, где изначально был mouseDragged? Есть ли способ отменить событие mouseDragged?

Возможно / необходимо "подделать" прерывающее событие mouseRelease?

Надеюсь, что есть решение, которое не заставит готовить больше кофе ....

Привет, Flo

EDIT: хорошо, есть код для вас:

Интерфейс, реализованный узлами и страницей, упрощает работу:

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;
}

Это намного больше, но я думаю, это была интересная часть. Спасибо за вашу помощь!

Ответы [ 3 ]

2 голосов
/ 26 февраля 2012

Я не уверен, что понимаю ваш подход, но на ум приходят две вещи:

  • Вы можете consume() «событие», чтобы оно не было обработано способом по умолчанию источником, который его создал. "

  • Вы можете push() свой собственный EventQueue и переопределить dispatchEvent(), чтобы изменить любое событие на пути к его конечному пункту назначения. Есть связанный пример здесь , и Глобальная диспетчеризация событий - превосходное руководство.

Добавление. Хотя это не относится к актуальной проблеме, существуют другие подходы к множественному выбору узлов:

  • GraphPanel использует перетаскивание мышью или нажатие клавиши Shift для выбора нескольких элементов, а также нажатие правой кнопкой мыши для отображения контекстного меню.

  • JGraph использует сдвиг для нескольких вариантов выбора; com.mxgraph.examples.swing.GraphEditor является примером.

  • Этот пример предлагает, как можно использовать JInternalFrame.

0 голосов
/ 29 августа 2014

Из того, что я заметил, когда выполняется перетаскивание, MouseEvent s больше не отправляются слушателям.Вместо этого вы можете использовать DragSourceListener, который имеет несколько полезных методов.Вероятно, вам интересен dragDropEnd, который вызывается после успешного завершения операции перетаскивания.

0 голосов
/ 26 февраля 2012

Некоторые вещи, которые меня интересуют: 1. В коде вашей страницы у вас есть lastDragPosition = new Point (0, 0);Зачем?2. Почему бы вам просто не использовать метод mouseExited (MouseEvent e) для имитации разрыва в перетаскивании и просто запустить поток, который проверяет, перетаскивали ли вы уже или нет, и, если вы уже закончили перетаскивание, соедините точки

...