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

Hovercraft Full Of Eels がコメントで指摘しているように、これはYou Are n't Gonna Need Itの典型的なケースです。誰がいつそれを使用するかを明確に理解する前に機能を実装することは、一般的にノーノーです。この状況では、コメントで概説した使用例を考慮して、いくつかのオプションがあります。

  • このクラスをあらゆる場所で使用し、わずかに高いオーバーヘッドを受け入れます。おそらく、パフォーマンスへの影響はあまり気にしませんが、それは非常に小さい可能性があります。ただし、これにより、残りのコード全体でこのクラスへの依存度が高まります。つまり、後日回帰を導入すると、多数の関連システムが壊れる危険性があります。

  • クラスのコンシューマが使用する機能を指定し (ダブルクリックなど)、コンシューマが必要としない機能を無効にできるようにします。これにより、クラスが複雑になり、バグが発生する可能性が高くなり、テストがより困難になります (ほとんど不可能ではありません)。クラス間の一貫性が非常に必要な場合は、これがオプションになる可能性があります。

  • 追加機能が必要な場合はこのクラスを使用し、他の場所では通常のクラスを使用しMouseAdapterます。これは、特に特定の動作ケースがカスタム クラスで明確に定義されていない場合に、おそらく最適なオプションです。これにより、クラスへの依存が減り、クラスも内部的に簡素化されます。トレードオフは、コンシューマー クラス間でのマウス操作の処理方法の一貫性が低下することと、MouseAdapterコンシューマー向けの を実装するためのコードがわずかに増えることです。これは、一般的に価値のあるトレードオフです。

于 2013-01-13T14:05:19.133 に答える
1

これらの追加機能が必要な場合、選択の余地はありません。これらの機能が必要ない場合は、この拡張リスナークラスを使用しても意味がありません。これも選択の余地がありません。

いくつかのメンバーフィールドといくつかの追加コードに注意してください。残りのJavaVMや他のコードと比較して、オーバーヘッドはほとんどありません...したがって、どちらを選択しても、実際には重要ではありません。

繰り返しになりますが、必要なものを選択してください。

于 2013-01-13T13:47:12.467 に答える