Кнопки удержания поворота Java - PullRequest
2 голосов
/ 06 апреля 2010

Я пытаюсь создать подкласс 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));
    }

}

Большое спасибо за ваше время.

edit: Выбор метода 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));
    }

}

Ответы [ 2 ]

1 голос
/ 06 апреля 2010

По крайней мере, одна хорошая практика - выполнять «работу», в этом случае вы выполняете actionPerformed-loop в runnable через SwingUtilies.invokeLater ().Таким образом, он выгружается в пул / очередь событий, и вы не блокируете основной поток awt, поэтому не блокируете свой графический интерфейс.

1 голос
/ 06 апреля 2010

Когда вы нажмете кнопку мыши, вы можете запустить таймер, который будет неоднократно вызывать ваши действия с необходимым вам интервалом, пока кнопка не будет отпущена. Тогда вы можете остановить таймер. Отправив его в таймер, вы можете отправить его в новый поток и не выполнять управление потоками самостоятельно.

...