【问题标题】:Swing - Update LabelSwing - 更新标签
【发布时间】:2012-02-13 13:28:05
【问题描述】:

我有一个消息标签和一个提交按钮。提交按钮将被多次按下,每次按下的操作最多可能需要一分钟。

当按钮按下时,我想将消息设置为空,任务完成后,我想将消息设置为“完成”。

private void submitActionPerformed(java.awt.event.ActionEvent evt) {
   message = "";
   updateMessageLabel();

   doTheTask();

   /* this update is apply to the label after completion */
   message = "Complete";
}

是否可以在submitActionPerformed() 方法运行之前(或在方法中)更新该消息标签,但在单击按钮之后?

【问题讨论】:

标签: java swing event-dispatch-thread concurrency


【解决方案1】:

虽然Swing concurrency tutorial 已经包含一些关于如何在 Swing 中处理并发的非常好的示例,但请在下面找到一个示例

  • 包含一个复选框以证明 UI 仍然存在
  • 有一个进度条,从SwingWorker更新
  • 有一个标签,在SwingWorker 完成后更新

    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JProgressBar;
    import javax.swing.SwingWorker;
    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.lang.reflect.InvocationTargetException;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    
    public class SwingWorkerExample {
      private static JProgressBar PROGRESS_BAR;
      private static JLabel OUTPUT_LABEL;
      private static JFrame createGUI(){
        JFrame testFrame = new JFrame( "TestFrame" );
    
        PROGRESS_BAR = new JProgressBar(  );
        PROGRESS_BAR.setMinimum( 0 );
        PROGRESS_BAR.setMaximum( 100 );
    
        OUTPUT_LABEL = new JLabel( "Processing" );
    
        testFrame.getContentPane().add( PROGRESS_BAR, BorderLayout.CENTER );
        testFrame.getContentPane().add( OUTPUT_LABEL, BorderLayout.SOUTH );
    
        //add a checkbox as well to proof the UI is still responsive
        testFrame.getContentPane().add( new JCheckBox( "Click me to proof UI is responsive" ), BorderLayout.NORTH );
    
    
    
        testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        return testFrame;
      }
    
      public static void main( String[] args ) throws InvocationTargetException, InterruptedException {
        EventQueue.invokeAndWait( new Runnable() {
          @Override
          public void run() {
            JFrame frame = createGUI();
    
            frame.pack();
            frame.setVisible( true );
          }
        } );
        //start the SwingWorker outside the EDT
        MySwingWorker worker = new MySwingWorker( PROGRESS_BAR, OUTPUT_LABEL );
        worker.execute();
      }
      private static class MySwingWorker extends SwingWorker<String, Double>{
        private final JProgressBar fProgressBar;
        private final JLabel fLabel;
        private MySwingWorker( JProgressBar aProgressBar, JLabel aLabel ) {
          fProgressBar = aProgressBar;
          fLabel = aLabel;
        }
    
        @Override
        protected String doInBackground() throws Exception {
          int maxNumber = 10;
          for( int i = 0; i < maxNumber; i++ ){
            Thread.sleep( 2000 );//simulate long running process
            double factor = ((double)(i+1) / maxNumber);
            System.out.println("Intermediate results ready");
            publish( factor );//publish the progress
          }
          return "Finished";
        }
    
        @Override
        protected void process( List<Double> aDoubles ) {
          //update the percentage of the progress bar that is done
          int amount = fProgressBar.getMaximum() - fProgressBar.getMinimum();
          fProgressBar.setValue( ( int ) (fProgressBar.getMinimum() + ( amount * aDoubles.get( aDoubles.size() - 1 ))) );
        }
    
        @Override
        protected void done() {
          try {
            fLabel.setText( get() );
          } catch ( InterruptedException e ) {
            e.printStackTrace();
          } catch ( ExecutionException e ) {
            e.printStackTrace();
          }
        }
      }
    }
    

【讨论】:

  • 流程实现并不像用户预期的那样工作:它们可能是列表中的几个(累积)值,但它只将 progressBar 值设置为第一个。相反,要么遍历所有,要么只使用最后一个
  • 刚刚注意到另一个故障 (IMO):调用启动工作器的方法是 execute(而不是运行)
  • @kleopatra SwingWorker 类的类 javadoc 同意你的观点,所以我将调整代码。好收获(再次)
  • @Robin 如果我的长时间运行任务是数据库选择事务,你能告诉我如何使用你用来模拟长时间运行任务的循环。
  • @SyedMuhammadMubashir 如果您有任何问题,请发帖
【解决方案2】:

是的,您可以使用SwingWorker 线程执行此操作,在currentThreadexecute() 方法中执行所有预submitActionPerformed() 活动(例如更新标签),并使用worker @ 作为后台作业调用doTheTask() 987654328@。

我建议您阅读此文档以获取有关 SwingWorker Thread 的参考

【讨论】:

  • 最好链接到最新版本的JavaDocs。我已将您的答案编辑为指向 J2SE 7。有关获取最新文档链接的提示,请参阅 point 2 of advantages
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
  • 2017-09-17
  • 2012-08-09
  • 2017-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多