Передача событий родителю

Я хотел бы создать приложение, в котором некоторые события должны обрабатываться так, как если бы они были доставлены в родительские контейнеры. Например, у меня есть JPanel, который содержит JLabel. Верхняя JPanel реализует mousepress и перетаскивание прямо сейчас. Что мне нужно сделать, чтобы события выглядели так, как будто они прибыли в JPanel вместо самой метки. (изменение исходного объекта важно)

есть ли лучшее решение, чем фактическая реализация событий и репликация их в родителе? (это было бы утомительно после некоторых объектов с >5 детьми).

3 ответов


в прослушивателе событий вы можете отправить событие родительскому компоненту.

будучи myEvent аргумент функции обработки событий:

Component source=(Component)myEvent.getSource();
source.getParent().dispatchEvent(myEvent);

но это решение подразумевает создание нового EventListener для каждого добавляемого элемента.

таким образом, вы можете создать один обработчик событий и повторно использовать его, добавив его ко всем выбранным детям, например:

final Container parent=this; //we are a the parent container creation code
MouseListener myCommonListener=new MouseListener() {
    @Override
    public void mouseClicked(MouseEvent e) {
        parent.dispatchEvent(e);
    }
    @Override
    public void mouseEntered(MouseEvent e) {
        parent.dispatchEvent(e);
    }
    @Override
    public void mouseExited(MouseEvent e) {
        parent.dispatchEvent(e);
    }
    @Override
    public void mousePressed(MouseEvent e) {
        parent.dispatchEvent(e);
    }
    @Override
    public void mouseReleased(MouseEvent e) {
        parent.dispatchEvent(e);
    }
};

JLabel label=new JLabel("This is the first Label");
label.addMouseListener(myCommonListener);

JLabel label2=new JLabel("This is the second Label");
label2.addMouseListener(myCommonListener);
//... and so on 

вы должны преобразовать событие перед отправкой его к родителю. Преобразование включает в себя перевод координат в parent-relative.

public class RedispatchingMouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener{

    public void mouseClicked(MouseEvent e) {
        redispatchToParent(e);
    }

    public void mousePressed(MouseEvent e) {
        redispatchToParent(e);
    }

    public void mouseReleased(MouseEvent e) {
        redispatchToParent(e);
    }

    public void mouseEntered(MouseEvent e) {
        redispatchToParent(e);
    }

    public void mouseExited(MouseEvent e) {
        redispatchToParent(e);
    }

    public void mouseWheelMoved(MouseWheelEvent e){
        redispatchToParent(e);
    }

    public void mouseDragged(MouseEvent e){
        redispatchToParent(e);
    }

    public void mouseMoved(MouseEvent e) {
        redispatchToParent(e);
    }

    private void redispatchToParent(MouseEvent e){
        Component source = (Component) e.getSource();
        MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent());
        source.getParent().dispatchEvent(parentEvent);
    }
}

события мыши автоматически нацелены на самый глубокий компонент, который присвоен слушателей мыши.

из-за этого, чтобы достичь своей цели, вы можете просто удалить все прослушиватели мыши на JLabel, и он никогда не будет выбран в качестве цели для событий мыши.

следующий код отключит прослушиватели мыши на заданных компонентах и их потомках рекурсивно:

private void disableMouseForComponent(Component... components) {
    for (Component c : components) {
        if (c instanceof Container) {
            disableMouseForComponent(((Container) c).getComponents());
        }
        for (MouseListener l : c.getMouseListeners()) {
            c.removeMouseListener(l);
        }
        for (MouseMotionListener l : c.getMouseMotionListeners()) {
            c.removeMouseMotionListener(l);
        }
    }
}