2010-04-06 122 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。