Domanda

Sto cercando di creare una sottoclasse di JButton o AbstractButton che chiamerei specificato .actionPerformed fintanto che il mouse si tiene premuto il pulsante.

Finora pensavo di estendere JButton, l'aggiunta di un listener del mouse sulla creazione (all'interno costruttore) e la chiamata actionPerformed mentre il mouse è in basso. Finora mi è venuta in questo, ma mi è stato wondwering se ero sulla strada giusta e se sì, come implementare correttamente il "premuto" logica.

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));
    }

}

Grazie mille per il vostro tempo.

modifica: La scelta del metodo di timer mi si avvicinò con un'implementazione di lavoro:

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));
    }

}
È stato utile?

Soluzione

Quando si preme il mouse si potrebbe avviare un timer che richiama la vostra azione ripetutamente a intervalli è necessario fino a che il pulsante è lasciato andare. Poi si può fermare il timer. Inviando ad un timer, è possibile sottoporlo ad un nuovo thread e non fare la gestione dei thread da soli.

Altri suggerimenti

Almeno un buona pratica è quella di fare il 'lavoro', in questo caso si actionPerformed-loop in un eseguibile tramite lo SwingUtilies.invokeLater (). In questo modo si ottiene scaricato all'evento ThreadPool / coda e non sei il blocco del thread principale awt in modo da non stai bloccando la vostra interfaccia grafica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top