1

考虑下面的 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() {
    }
}
4

2 回答 2

2

正如充满鳗鱼的气垫船在评论中指出的那样,这是《你不需要它》的经典案例。在您清楚地知道谁将使用它以及何时使用它之前实施功能通常是禁忌。在这种情况下,考虑到您在评论中概述的用例,您有几个选择:

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

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

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

于 2013-01-13T14:05:19.133 回答
1

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

请注意,一些成员字段和一些额外的代码,与 Java VM 的其余部分和其他代码相比,它几乎没有开销......所以任何选择:这并不重要!

再说一遍:选择你需要的!

于 2013-01-13T13:47:12.467 回答