【问题标题】:Getting the system time in action listener获取系统时间监听器
【发布时间】:2013-03-14 17:29:22
【问题描述】:

我有一个实现Actionlistener 的类。单击此类中的按钮后,我希望它在我指定的精确时间,更早和其他地方执行某些操作。所以我做了这些课程:

class DoSomething implements ActionListener{
     public void actionPerformed(ActionEvent a){
     while(true){
         String test = obtainTime.time;

    if(test.matches("(.*)17:29:30(.*)")){
         Class.doSomethingMethod();
    }
        //Rest of the code
     }
     }
}

class ObtainTime{
     static DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
     static Calendar cal = Calendar.getInstance();
     static String time = dateFormat.format(cal.getTime());
}

所以问题是,我只得到点击它的时间。第二件事是按钮变得不可点击,因为它仍在运行,有没有办法让它在代码仍在后台运行时再次可点击?感谢您的帮助。

【问题讨论】:

  • 你需要使用线程。
  • 你永远不会设置那些静态字段

标签: java swing time system actionlistener


【解决方案1】:

如果您正在做一些快速的事情和/或需要您在达到目标时间时更新用户界面的事情,您想使用Java Swing Timer。更多相关文档在这里:Oracle's Swing Timer tutorial。如果您正在执行一项长时间运行的任务,您将需要遵循 andersoj 的建议并使用预定的执行程序。

【讨论】:

    【解决方案2】:

    您的第一个问题:虽然令人困惑,但我想您是在问为什么您只获得第一次按下按钮时所测量的时间。答案是因为当你第一次按下按钮时,你加载了ObtainTime 类。当您加载该类时,静态初始化程序运行一次且仅一次。行:

    static String time = dateFormat.format(cal.getTime());
    

    是一个静态初始化器。你的意思可能更像是这样的:

    class DoSomething implements ActionListener{
    
      private final ScheduledExecutor scheduler = executors.newSingleThreadScheduledExecutor();
      private final long timeToRunAction;
    
       DoSomething(long timeToRunAction) {
         this.timeToRunAction = timeToRunAction;
       }
    
       public void actionPerformed(ActionEvent a)
       {
         long currentTime = System.currentTimeMillis();
         long delayTime = timeToRunAction - currentTime;
         scheduler.schedule(new Runnable() {
             public void run() { Class.doSomethingMethod(); }
         }, delayTime, TimeUnit.MILLISECONDS);
       }
    }
    

    如果你使用这个类,那么当你实例化它时,你在构造函数中指定目标时间。您可能希望它更具动态性,这很好,您只需使 timeToRunAction 字段可变并提供一种设置它的方法。此处的时间以从 unix 纪元开始的毫秒数指定。如果你需要做一些日历魔术来计算你的目标时间,我已经把它省略了。

    您的第二个问题:我强烈建议您使用ScheduledExecutor.schedule() 来执行此操作,而不是滚动您自己的并发。您需要使用日历来计算正确的延迟时间(可能以毫秒为单位)来安排活动。

    【讨论】:

      【解决方案3】:

      如果你想并行地做几件事,你必须使用线程。你可以通过使用Thread 扩展你的类或实现Runnable interface 来做到这一点 两种方式的好教程都可以在here找到。

      要获取与您的模式匹配的甲酸盐时间和日期,请查看this document,您可以在其中找到用于格式化日期和时间的 java 模式。

      【讨论】:

      • 日期和时间的格式不是问题。问题是我只得到点击按钮的时间,所以如果我说让它告诉我 while 循环内每秒的时间,它每次都会打印相同的时间。
      • 您能否更新您的问题以更明确地说明“正常工作”是什么样的?我想你问了两个问题,一个是关于“我只有点击它的时间”,我不知道如何解释;还有一个关于并发的,@Dworza 和我回答了。
      • 好的,我知道这可能有点令人困惑。所以我的意思是当我得到 18:40:45 的 getTime.time 时,它​​每次都打印 18:40:45,正如有人解释的那样,因为初始化程序是静态的。
      【解决方案4】:

      看起来您正在使用 Swing 作为您的 GUI API。你应该使用javax.swing.SwingWorker 来实现你正在寻找的东西。可以这样做:

      import javax.swing.*;
      import java.util.*;
      import java.text.*;
      import java.awt.*;
      
      public class SWorker extends JFrame
      {
          JLabel label ;
          DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
          Calendar cal = Calendar.getInstance();
          static SwingWorker worker;
          public void createAndShowGUI()
          {
              setTitle("SwingWorker Demo");
              label = new JLabel();
              getContentPane().add(label,BorderLayout.NORTH);
              setSize(300,200);
              worker = new SwingWorker<String, String>() 
              {
                  @Override
                  public String doInBackground() 
                  {
                     cal = Calendar.getInstance();
                     String test = dateFormat.format(cal.getTime());
                     while (!(test.matches("(.*)23:41:30(.*)")) && ! isCancelled())
                     {
                         publish(new String[] {test});
                          Thread.sleep(5);//Added to sleep the thread for 5 ms so that load could be shed from processor..
                         cal = Calendar.getInstance();
                         test = dateFormat.format(cal.getTime());
                     }
                     return test;
                  }
      
                  @Override
                  public void done() //This method is called when doInBackground() finishes. i.e when pattern is matched
                  {
                      try
                      {
                          //Call here the method that you want to call after the time matches.
                          label.setText(get() + " Time's up ...!!");  
                      }
                      catch (Exception ex){}
      
                  }
                  @Override
                  public void process(java.util.List<String> chunks)
                  {
                      label.setText(chunks.get(chunks.size()-1));
                  }
              };
              String time = dateFormat.format(cal.getTime());
              label.setText(time);
              setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              setVisible(true);
          }
          public void start()
          {
              worker.execute();
          }
          public static void main(String st[])
          {
              SwingUtilities.invokeLater( new Runnable()
              {
                  @Override
                  public void run()
                  {
                      SWorker sWorker = new SWorker();
                      sWorker.createAndShowGUI();
                      sWorker.start();
                  }
              });
          }
      }
      

      想知道更多SwingWorker的使用方法请看这个官方tutorial on SwingWorker

      【讨论】:

      • 你真的不想运行 while !test.matches() 循环,它只会无缘无故地咀嚼处理器。
      • @andersoj 是的,它会的.. 但是如果用户在选择时间方面给予一些灵活性,比如(.*)23:42:(.*),那么我们可以很高兴地在doInBackground() 中使用Thread.sleep(),这将减轻负担处理器肯定。
      • 是的,你可以,但是 JDK 提供了更安全、更高效的不错的原语。请参阅TimerScheduledExecutor。如果您想要“草率”匹配时间,您可以为计时器或执行程序指定您满意的最早时间。
      • 我从 Java 教程(官方教程)中得到的,只要考虑的 API 是 swing 并且必须在 background 中执行一些较长的过程,那么 SwingWorker 是最好的选择它。如果你启动oracledocs.oracle.com/javase/tutorial/uiswing/concurrency/…这个教程页面中给出的程序,你会看到它也在猛烈地吞噬处理器。所以这意味着,这些代码误导了程序员?? .
      • SwingWorker 对于在 GUI 后台运行的活动来说是一个很好且简单的选择,尤其是当它们需要将进度反馈给 GUI 时。但是,它不提供调度基础设施。使用Executor(SwingWorker 在幕后使用)也是完全可以接受的。转到Executor 时唯一会失去的是,如果你回调 UI,你必须小心,你需要确保你回到 EDT,可能是 SwingUtilities.invokeLater()
      猜你喜欢
      • 2016-01-28
      • 1970-01-01
      • 2021-03-21
      • 1970-01-01
      • 1970-01-01
      • 2012-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多