Swing - 更新标签(Label)

8

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

当按钮被按下时,我希望将消息设置为空,并在任务完成后将其设置为“完成”。

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

   doTheTask();

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

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


2
我可能推断过多了,但似乎进度条会在这里很好用 (http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html)? - Zack Macomber
@ZackMacomber 那是下一步。 - Berek Bryan
2个回答

13

尽管Swing并发教程已经包含了一些非常好的样例,展示如何处理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();
      }
    }
  }
}

3
流程实施并没有完全按照用户的预期工作:列表中可能会有几个(累积的)值,但它只将进度条值设置为第一个。相反,要么循环遍历所有值,要么仅使用最后一个值。 - kleopatra
刚刚注意到另一个故障(依我看):启动worker的方法是execute(而不是run)。 - kleopatra
1
@kleopatra SwingWorker类的Javadoc与您一致,因此我会调整代码。又发现了一个问题,干得好。 - Robin
@Robin,你能告诉我如何使用你用来模拟长时间运行任务的循环,如果我的长时间运行任务是数据库选择事务吗? - Syed Muhammad Mubashir
@SyedMuhammadMubashir 如果你有问题,请发一个。 - Robin

10

您可以使用SwingWorker线程来实现此操作,将所有的预submitActionPerformed()活动,在currentThreadexecute()方法中更新标签,并使用工作线程Thread调用doTheTask()作为后台任务。

我建议您参考这篇文档了解有关SwingWorker Thread的内容。


2
最好链接到最新版本的JavaDocs。我已经编辑了你的答案,指向J2SE 7。关于获取最新文档链接的提示,请参见优点的第二点 - Andrew Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接