两个JButton使用相同的actionListener来启动/停止计时器

时间:2014-11-08 19:03:44

标签: java swing timer

我对Java很新,可以提供一些帮助。我试图让定时器倒计时从设定的时间到0.我有这个功能工作正常,但我想添加功能,让我可以在计时器停止计时器。

这是我的代码(我试图使用MVC实现此目的)

这是控制部分:

import java.awt.event.*;
import javax.swing.*;

public class StartButton extends JButton implements ActionListener
{
    private TimerModel model;
    private Timer timer;
    private boolean isStarted;

    public StartButton(String buttonText, TimerModel model)
    {
        super(buttonText);
        addActionListener(this);
        this.model = model;
        isStarted = false;
    }

    public void actionPerformed(ActionEvent evt)
    {
        if(!isStarted) 
        {
            timer = new Timer(1000, this);
            timer.start();
            isStarted = true;
        }

        model.timerCountdown();
    }

    public void stopTimer()
    {
        timer.stop();
    }
}

我在网上看了一些其他类似的问题,我在构造函数中尝试了这个(注意:我没有使用实现ActionListener,并删除了上面的actionPerformed方法):

if(buttonText.equals("Start"))
    {
        addActionListener(new ActionListener() 
        {
            public void actionPerformed(ActionEvent e)
            {
               if(!isStarted) 
               {
                   timer = new Timer(1000, this);
                   timer.start();
                   isStarted = true;
               }

               model.timerCountdown(); 
            }
        });
    }

    if(buttonText.equals("Stop"))
    {
        addActionListener(new ActionListener() 
        {
            public void actionPerformed(ActionEvent e)
            {
               timer.stop(); 
            }
        });
    }

现在这部分处理倒计时确定,但是当我点击停止按钮时它会显示异常(See stack trace here),并且它会继续倒计时。

我的知识有限,但我想这与我尝试停止计时器的方式有关。

如果有人能指出我正确的方向,或者至少向我解释为什么会发生这种情况,我将不胜感激。

2 个答案:

答案 0 :(得分:3)

同样,如果您不改变JButton本身的基本行为,例如如何绘制它,而只是在按下时更改按钮的标题和行为,那么请不要这样做。扩展JButton。而是给每个按钮赋予自己的Action,一个来自AbstractAction的类的对象。考虑这些人类似于类固醇的ActionListeners。它们具有与ActionListeners相同的功能,因为它们可以轻松更改按钮的标题,无论是否启用,它的助记符,图标,......

例如:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.*;

import javax.swing.*;

@SuppressWarnings("serial")
public class MyTimerGui {
   private static final String TITLE = "Flashing Label";
   private static final int TIMER_DELAY = 200;
   private static final int GAP = 3;
   private static final float LABEL_POINTS = 32F;
   private JPanel mainPanel = new JPanel();
   private JLabel flashyLabel = new JLabel(TITLE, SwingConstants.CENTER);
   private Timer timer = new Timer(TIMER_DELAY, new TimerListener());

   public MyTimerGui() {
      Font font = flashyLabel.getFont();
      font = font.deriveFont(LABEL_POINTS);
      flashyLabel.setFont(font);
      flashyLabel.setOpaque(true);

      JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
      buttonPanel.add(new JButton(new StartAction(this, "Start", KeyEvent.VK_S)));
      buttonPanel.add(new JButton(new StopAction(this, "Stop", KeyEvent.VK_T)));
      buttonPanel.add(new JButton(new ExitAction(this, "Exit", KeyEvent.VK_X)));

      mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
      mainPanel.setLayout(new BorderLayout());
      mainPanel.add(flashyLabel, BorderLayout.CENTER);
      mainPanel.add(buttonPanel, BorderLayout.PAGE_END);
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   public void start() {
      timer.start();
   }

   public void stop() {
      timer.stop();
      flashyLabel.setForeground(null);
      flashyLabel.setBackground(null);
   }

   public void exit() {
      timer.stop();
      Window win = SwingUtilities.getWindowAncestor(mainPanel);
      win.dispose();
   }

   private class TimerListener implements ActionListener {
      private final Color foreground1 = Color.green;
      private final Color background1 = Color.red;

      @Override
      public void actionPerformed(ActionEvent aEvt) {
         Color fg = flashyLabel.getForeground();
         if (foreground1.equals(fg)) {
            flashyLabel.setForeground(null);
            flashyLabel.setBackground(null);
         } else {
            flashyLabel.setForeground(foreground1);
            flashyLabel.setBackground(background1);
         }
      }
   }

   private class StartAction extends AbstractAction {
      private MyTimerGui myTimerGui;

      public StartAction(MyTimerGui myTimerGui, String name, int mnemonic) {
         super(name);
         putValue(MNEMONIC_KEY, mnemonic);
         this.myTimerGui = myTimerGui;
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         myTimerGui.start();
      }
   }

   private class StopAction extends AbstractAction {
      private MyTimerGui myTimerGui;

      public StopAction(MyTimerGui myTimerGui, String name, int mnemonic) {
         super(name);
         putValue(MNEMONIC_KEY, mnemonic);
         this.myTimerGui = myTimerGui;
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         myTimerGui.stop();
      }
   }

   private class ExitAction extends AbstractAction {
      private MyTimerGui myTimerGui;

      public ExitAction(MyTimerGui myTimerGui, String name, int mnemonic) {
         super(name);
         putValue(MNEMONIC_KEY, mnemonic);
         this.myTimerGui = myTimerGui;
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         myTimerGui.exit();
      }
   }

   private static void createAndShowGui() {
      MyTimerGui myTimerGui = new MyTimerGui();

      JFrame frame = new JFrame("MyTimer");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(myTimerGui.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

答案 1 :(得分:2)

我同意那些说你不应该延长JButton的评论。也许逻辑应该在你的应用程序的主类中执行,这个类与处理组件的创建和存储的类相同。

但我离题了。要回答你的问题,我认为有两种方法可以解决这个问题。要么(A)在您的类中存储actionListener,就像在代码中一样;或者(B)在对象本身之外写一个actionListener

您是否尝试在主类构造函数中实现此构造函数?

我认为你需要类似下面的内容(这也是主要的类):

StartButton start = new JButton("Start");
StopButton stop = new JButton("Stop");

start.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        // called when the button is pressed
        buttonPressed();
    }
});

stop.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        // called when the button is pressed
        buttonPressed();
    }
});

然后你会在同一个类中编写这个方法:

private void buttonPressed() {
    System.out.println("Button pressed!");
}

我刚刚对此进行了快速测试,因此我可以确认此方法有效。

PS:我还建议让按钮包含boolean state,而不是检查按钮的文本,如果你打算继续使用StartButton及相关的类。