2

我正在尝试创建一个 JButton 或 AbstractButton 的子类,只要将鼠标按住按钮,它就会调用指定的 .actionPerformed 。

到目前为止,我正在考虑扩展 JButton,在创建时添加鼠标侦听器(在构造函数内部)并在鼠标按下时调用 actionPerformed。到目前为止,我想出了这个,但我想知道我是否走在正确的轨道上,如果是这样,如何正确实现“按住”逻辑。

package components;

import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;

public class HoldButton extends JButton {

    private class HeldDownMouseListener implements MouseListener {

        private boolean mouseIsHeldDown;

        private HoldButton button;

        private long millis;

        public HeldDownMouseListener(HoldButton button, long millis) {
            this.button = button;
            this.millis = millis;
        }

        @Override
        public void mouseClicked(MouseEvent arg0) { }

        @Override
        public void mouseEntered(MouseEvent arg0) { }

        @Override
        public void mouseExited(MouseEvent arg0) { }

        @Override
        public void mousePressed(MouseEvent arg0) {
            mouseIsHeldDown = true;
//          This should be run in a sub thread?
//          while (mouseIsHeldDown) {
//              button.fireActionPerformed(new ActionEvent(button, ActionEvent.ACTION_PERFORMED, "heldDown"));
//              try {
//                  Thread.sleep(millis);
//              } catch (InterruptedException e) {
//                  e.printStackTrace();
//                  continue;
//              }
//          }
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
            mouseIsHeldDown = false;
        }

    }

    public HoldButton() {
        addHeldDownMouseListener();
    }

    public HoldButton(Icon icon) {
        super(icon);
        addHeldDownMouseListener();
    }

    public HoldButton(String text) {
        super(text);
        addHeldDownMouseListener();
    }

    public HoldButton(Action a) {
        super(a);
        addHeldDownMouseListener();
    }

    private void addHeldDownMouseListener() {
        addMouseListener(new HeldDownMouseListener(this, 300));
    }

}

非常感谢您的时间。

编辑:选择 Timer 方法我想出了一个可行的实现:

package components;

import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;

public class HoldButton extends JButton {

    private static final long serialVersionUID = 1L;

    public static final long CLICK_LAG = 300;

    public static final long INITIAL_FIRE_DELAY = 500;

    public static final double FIRE_DELAY_STEP_MULTIPLIER = 25;

    public static final long MIN_FIRE_DELAY = 100;

    private class HeldDownMouseListener implements MouseListener {

        private class HeldDownCheckerTask extends TimerTask {

            private HeldDownMouseListener listener;

            public HeldDownCheckerTask(HeldDownMouseListener listener) {
                this.listener = listener;
            }

            @Override
            public void run() {
                long delay = INITIAL_FIRE_DELAY;

                while (listener.isMouseHeldDownOnButton()) {
                    listener.fireMouseHeldDown();

                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    if (delay > MIN_FIRE_DELAY) {
                        final long decrease = Math.round(FIRE_DELAY_STEP_MULTIPLIER * Math.pow(INITIAL_FIRE_DELAY / delay, 2));
                        delay = Math.max(delay - decrease, MIN_FIRE_DELAY);
                    }
                }
            }

        }

        private boolean mouseIsHeldDown;

        private boolean mouseIsOnButton;

        private HoldButton button;

        private Timer timer;

        public HeldDownMouseListener(HoldButton button) {
            this.button = button;
        }

        public boolean isMouseHeldDownOnButton() {
            return mouseIsHeldDown && mouseIsOnButton;
        }

        private void cancelTimer() {
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
        }

        private void fireMouseHeldDown() {
            button.fireActionPerformed(new ActionEvent(button, ActionEvent.ACTION_PERFORMED, "heldDown"));
        }

        @Override
        public void mouseClicked(MouseEvent arg0) {
            cancelTimer();
        }

        @Override
        public void mouseEntered(MouseEvent arg0) {
            mouseIsOnButton = true;
        }

        @Override
        public void mouseExited(MouseEvent arg0) {
            mouseIsOnButton = false;
        }

        @Override
        public void mousePressed(MouseEvent arg0) {
            cancelTimer();
            mouseIsHeldDown = true;
            timer = new Timer();
            timer.schedule(new HeldDownCheckerTask(this), CLICK_LAG);
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
            mouseIsHeldDown = false;
        }

    }

    public HoldButton() {
        addHeldDownMouseListener();
    }

    public HoldButton(Icon icon) {
        super(icon);
        addHeldDownMouseListener();
    }

    public HoldButton(String text) {
        super(text);
        addHeldDownMouseListener();
    }

    public HoldButton(Action a) {
        super(a);
        addHeldDownMouseListener();
    }

    private void addHeldDownMouseListener() {
        addMouseListener(new HeldDownMouseListener(this));
    }

}
4

2 回答 2

1

按下鼠标时,您可以启动一个计时器,该计时器以您需要的时间间隔重复调用您的操作,直到松开按钮。然后你可以停止计时器。通过将其提交给计时器,您可以将其提交给新线程,而无需自己进行线程管理。

于 2010-04-06T19:05:55.710 回答
1

至少一种好的做法是做“工作”,在这种情况下,您可以通过 SwingUtilies.invokeLater() 在可运行对象中执行 actionPerformed-loop。这样它就会被卸载到事件线程池/队列,并且您不会阻塞 awt 主线程,因此您不会阻塞您的 GUI。

于 2010-04-06T19:08:40.790 回答