详细的MouseListener实现值得开销吗?

时间:2013-01-13 13:39:59

标签: java swing awt mouseevent mouse-listeners

考虑下面的MouseListener。我的问题是:具有此监听器提供的额外功能,其中一些您不需要,值得拥有这些功能所带来的内存和处理开销?或者应该避免这种“冗长”的实施?

import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Timer;

/**
 * This is an overkill class that is useful for distinguishing between buttons and includes functions for hold and double-click events.
 *
 * @author Paranoid Android
 */
public class ParanoidMouseListener extends MouseAdapter {

    public static final int LEFT = MouseEvent.BUTTON1;
    public static final int MIDDLE = MouseEvent.BUTTON2;
    public static final int RIGHT = MouseEvent.BUTTON3;

    private DoubleClickTimer leftDouble = new DoubleClickTimer();
    private DoubleClickTimer middleDouble = new DoubleClickTimer();
    private DoubleClickTimer rightDouble = new DoubleClickTimer();

    private MouseEvent event;
    private int pressedButton;
    private Component pressed;
    private boolean dragging;


    /**
     * This method allows methods to ignore the MouseEvent when not needed.
     *
     * @return the latest mouse event.
     */
    public MouseEvent getEvent() {
        return event;
    }

    private HoldTimer leftHold = new HoldTimer() {

        @Override
        public void perform() {
            onLeftHold();
        }
    };
    private HoldTimer middleHold = new HoldTimer() {

        @Override
        public void perform() {
            onMiddleHold();
        }
    };
    private HoldTimer rightHold = new HoldTimer() {

        @Override
        public void perform() {
            onRightHold();
        }
    };

    @Override
    public final void mouseClicked(MouseEvent event) {
        this.event = event;
        switch (event.getButton()) {
            case LEFT:
                if (leftDouble.isRunning()) {
                    leftDouble.stop();
                    onLeftDoubleClick();
                } else {
                    leftDouble.start();
                    onPureLeftClick();
                }
                break;
            case MIDDLE:
                if (middleDouble.isRunning()) {
                    middleDouble.stop();
                    onMiddleDoubleClick();
                } else {
                    middleDouble.start();
                    onPureMiddleClick();
                }
                break;
            case RIGHT:
                if (rightDouble.isRunning()) {
                    rightDouble.stop();
                    onRightDoubleClick();
                } else {
                    rightDouble.start();
                    onPureRightClick();
                }
                break;
        }
    }

    @Override
    public final void mousePressed(MouseEvent event) {
        this.event = event;
        pressedButton = event.getButton();
        pressed = event.getComponent();
        switch (event.getButton()) {
            case LEFT:
                leftHold.start();
                onLeftPress();
                break;
            case MIDDLE:
                middleHold.start();
                onMiddlePress();
                break;
            case RIGHT:
                rightHold.start();
                onRightPress();
                break;
        }
    }

    @Override
    public final void mouseReleased(MouseEvent event) {
        this.event = event;
        pressedButton = -1;
        Component src = event.getComponent();
        boolean contains = src.contains(event.getPoint());
        switch (event.getButton()) {
            case LEFT:
                leftHold.stop();
                onLeftRelease();
                if (!dragging && src == pressed && contains) onLeftClick();
                break;
            case MIDDLE:
                middleHold.stop();
                onMiddleRelease();
                if (!dragging && src == pressed && contains) onMiddleClick();
                break;
            case RIGHT:
                rightHold.stop();
                onRightRelease();
                if (!dragging && src == pressed && contains) onRightClick();
                break;
        }
        dragging = false;
    }

    @Override
    public final void mouseMoved(MouseEvent event) {
        this.event = event;
        moved();
    }

    @Override
    public final void mouseDragged(MouseEvent event) {
        this.event = event;
        dragging = true;
        switch (pressedButton) {
            case LEFT:
                onLeftDrag();
                break;
            case MIDDLE:
                onMiddleDrag();
                break;
            case RIGHT:
                onRightDrag();
                break;
        }
    }

    @Override
    public final void mouseEntered(MouseEvent event) {
        this.event = event;
        entered();
    }

    @Override
    public final void mouseExited(MouseEvent event) {
        this.event = event;
        exited();
    }

    private int getDoubleClickInterval() {
        String property = "awt.multiClickInterval";
        return (int) Toolkit.getDefaultToolkit().getDesktopProperty(property);
    }

    private class DoubleClickTimer extends Timer {

        public DoubleClickTimer() {
            super(getDoubleClickInterval(), null);
            this.setRepeats(false);
        }
    }

    public int getHoldInitialDelay() {
        return 300;
    }

    public int getHoldQueueDelay() {
        return 60;
    }

    private class HoldTimer extends Timer {

        public HoldTimer() {
            super(getHoldQueueDelay(), null);

            this.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    perform();
                }
            });
            this.setInitialDelay(getHoldInitialDelay());
        }

        public void perform() {
        }
    }

    public void moved() {
    }

    public void entered() {
    }

    public void exited() {
    }

    public void onLeftHold() {
    }

    public void onMiddleHold() {
    }

    public void onRightHold() {
    }

    public void onLeftClick() {
    }

    public void onMiddleClick() {
    }

    public void onRightClick() {
    }

    public void onPureLeftClick() {
    }

    public void onPureMiddleClick() {
    }

    public void onPureRightClick() {
    }

    public void onLeftDoubleClick() {
    }

    public void onMiddleDoubleClick() {
    }

    public void onRightDoubleClick() {
    }

    public void onLeftPress() {
    }

    public void onMiddlePress() {
    }

    public void onRightPress() {
    }

    public void onLeftRelease() {
    }

    public void onMiddleRelease() {
    }

    public void onRightRelease() {
    }

    public void onLeftDrag() {
    }

    public void onMiddleDrag() {
    }

    public void onRightDrag() {
    }
}

2 个答案:

答案 0 :(得分:2)

正如Hovercraft Full Of Eels在评论中指出的那样,这是You Aren't Gonna Need It的经典案例。在明确了解谁将使用它以及何时使用它之前实现功能通常是禁止的。在这种情况下,考虑到您在评论中概述的用例,您有以下几种选择:

  • 在任何地方使用此类并接受稍高的开销。很可能你不太关心性能影响,这可能非常小。但是,这确实会在代码的其余部分中引入对此类的更大依赖性,这意味着如果您在以后引入回归,则存在破坏大量相关系统的风险。

  • 允许班级的消费者指出他们将使用哪些功能(例如,双击)并禁用消费者不想要的功能。这会给您的课程带来复杂性,并使其更容易出错,并且使测试变得更加困难(尽管几乎不可能)。如果类之间非常需要一致性,这可能是一种选择。

  • 需要添加的功能时使用此类,并在其他地方使用普通的MouseAdapter。这可能是您的最佳选择,尤其是在您的自定义类中未定义某些行为案例时。这减少了对类的依赖,并在内部简化了类。权衡的是消费者类之间处理鼠标交互的方式的一致性较低,以及为消费者实现MouseAdapter稍微多一些的代码 - 通常是值得的权衡。

答案 1 :(得分:1)

如果您需要这些附加功能,则别无选择!如果你不需要这些功能,那么使用这个扩展的监听器类是没有意义的,再也没有选择!

请注意一些成员字段和一些其他代码,与其他Java VM和其他代码相比,它几乎没有开销...所以要么选择:它并不重要!

再次:选择你需要的东西!