2010-04-06 211 views
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)); 
    } 

} 

非常感谢您的时间。

编辑:选择我想出了一个工作实现定时器方法:

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

} 
+1

嗯,我想你应该使用javax.swing.Timer而不是java.util.Timer。你应该把它设置为一个重复的时间(所以你不必自己调用sleep())。 javax.swing.Timer的优点是它将始终在Event Dispatch Thread内运行您的任务,这通常是对任何Swing EventListener的调用所期望的。 如果actionPerformed()访问或更改GUI组件,您当前的实现将调用actionPerformed _outside_ EDT。 – jfpoilpret 2010-04-07 07:35:05

回答

1

当鼠标被按下,你可以启动你需要的,直到按钮让间隔重复调用你的行动定时器走。然后你可以停止计时器。通过将其提交给定时器,您可以将其提交给新线程,而不是自己进行线程管理。

1

至少有一个好习惯是做'工作',在这种情况下,你可以通过SwingUtilies.invokeLater()将actionPerformed循环放入可运行的环境中。这样它就会被卸载到事件threadpool/queue,并且你不会阻塞awt主线程,所以你不会阻塞你的GUI。