0

私はJProgressBarに関するさまざまな記事を読みました...Javaで見つかった危険なコードを含みます。ここ。

ほとんどの場合、物事を適切に行うにはSwingWorkerが必要であると示されていますが、これは完全に理にかなっています。私はそれをよく理解しています。setProgress(value)を呼び出してプログレスバーを更新しても、ほとんどの場合、propertyChangeイベントがトリガーされないことがわかりました。setProgessに渡す値を確認しましたが、毎回確実に変化するので、イベントの発生が速すぎるかどうかわかりません。以下の関連コードを参照してください。ヘルプ/説明をいただければ幸いです。

class ProgBar extends SwingWorker
{
    public ProgBar()
    {
        addPropertyChangeListener(new PropertyChangeListener()
        {
           @Override
           public void propertyChange(PropertyChangeEvent evt)
           {
               if ("progress".equals(evt.getPropertyName()))
               {
                   int value = (Integer)evt.getNewValue();
                   System.out.println("propertyChange called with: " + value);
                   loginProg.setValue(value);
               }
           }
        });

        loginProg.setStringPainted(true);
        loginProg.setValue(0);
        setProgress(0);
    }

    @Override
    public Void doInBackground() throws InterruptedException
    {
        ...
        int count = 0;
        for (Folder f : folders)
        {
            ... // process 'f'
            setProgress((int)Math.min(((double)count/folders.length)*100.0, 100.0));
        }
        ...
        return null;
    }

    @Override
    public void done()
    {
        System.out.println("Done called.");
        setProgress(100);
        loginProg.setValue(100);
    }
}

これで呼び出されたJProgressBar;

private void jButtonActionPerformed(java.awt.event.ActionEvent evt) 
{                                             
        // Create new thread to run progess bar.
        // Otherwise won't be able to update progress bar.
        ProgBar pb = new ProgBar();
        pb.execute();
    }
}    

編集:
ええ、だから私はJavadocをもっとよく読むべきでした。

PropertyChangeListenersはイベントディスパッチスレッドで非同期に通知されるため、PropertyChangeListenersが呼び出される前に、setProgressメソッドへの複数の呼び出しが発生する可能性があります。パフォーマンスの目的で、これらのすべての呼び出しは、最後の呼び出し引数のみを使用して1つの呼び出しにまとめられます。

たとえば、次の呼び出し:
setProgress(1);
setProgress(2);
setProgress(3);

値が3の単一のPropertyChangeListener通知が発生する可能性があります。

IEsetProgressの起動が速すぎるという私の仮定は正しかった。ProgressMonitorがより良いソリューションかもしれません。

4

3 に答える 3

3

これは答えではなく、デモンストレーションsscceであり、私が何を意味していたかを示しています。

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;

import javax.swing.*;

public class TestProgBar {
   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            ProgBar progBar = new ProgBar();


            // **** this is key and where your code may be deficient ***
            JProgressBar prog = progBar.getProg(); 


            progBar.execute();
            JOptionPane.showMessageDialog(null, prog);
         }
      });
   }
}

class ProgBar extends SwingWorker<Void, Void> {
   private JProgressBar loginProg = new JProgressBar();

   public ProgBar() {
      addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
               int value = (Integer) evt.getNewValue();
               System.out.println("propertyChange called with: " + value);
               loginProg.setValue(value);
            }
         }
      });

      loginProg.setStringPainted(true);
      loginProg.setValue(0);
      setProgress(0);
   }

   public JProgressBar getProg() {
      return loginProg;
   }

   @Override
   public Void doInBackground() throws InterruptedException {
      int count = 0;
      int max = 5;
      Random random = new Random();

      // simulate uploading files
      while (count < 100) {
         count += random.nextInt(max);
         if (count > 100) {
            count = 100;
         }
         setProgress(count);
         Thread.sleep(400);
      }
      // for (Folder f : folders) {
      // setProgress((int) Math.min(((double) count / folders.length) * 100.0,
      // 100.0));
      // }
      return null;
   }

   @Override
   public void done() {
      System.out.println("Done called.");
      setProgress(100);
      loginProg.setValue(100);
   }
}

繰り返しますが、このコードは正常に機能し、ロードしたコードにエラーが表示されないことを示しています。エラーを分離してコードに組み込むことで、テストできるようにするために、さらに作業を行う必要があります。

于 2012-11-24T03:51:14.727 に答える
0

ええ、Javadocをもっとよく読むべきでした。

PropertyChangeListenersはイベントディスパッチスレッドで非同期に通知されるため、PropertyChangeListenersが呼び出される前に、setProgressメソッドへの複数の呼び出しが発生する可能性があります。パフォーマンスの目的で、これらのすべての呼び出しは、最後の呼び出し引数のみを使用して1つの呼び出しにまとめられます。

たとえば、次の呼び出し:
setProgress(1);
setProgress(2);
setProgress(3);
値が3の単一のPropertyChangeListener通知が発生する可能性があります。

IEsetProgressの起動が速すぎるという私の仮定は正しかった。ProgressMonitorがより良いソリューションかもしれません。これをSSCCEと私のプログラムで確認しました。どちらも、setProgressの起動が速すぎるため、setProgressに渡された最後の値のみがPropertyChangeイベントに渡されます。

于 2012-11-27T06:54:26.030 に答える
0

リスナーをすぐに呼び出したい場合は、次のことを試すことができます(これは私にとってはうまくいきました)。

setProgress(1);
firePropertyChange("progress", 0, 1);
于 2015-11-18T08:02:00.197 に答える