1. ホーム
  2. c#

[解決済み] WinFormsのプログレスバーを使うには?

2022-03-08 05:30:06

質問

外部ライブラリで行っている計算の進捗を表示したい。

例えば、ある計算メソッドを持っていて、それをFormクラスで100000個の値に対して使いたい場合、次のように書くことができます。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }            

    private void Caluculate(int i)
    {
        double pow = Math.Pow(i, i);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        progressBar1.Maximum = 100000;
        progressBar1.Step = 1;

        for(int j = 0; j < 100000; j++)
        {
            Caluculate(j);
            progressBar1.PerformStep();
        }
    }
}

計算のたびにステップを実行する必要があります。しかし、100000回の計算をすべて外部メソッドで行うとしたらどうでしょう。このメソッドをプログレスバーに依存させないためには、いつステップを実行すればいいのでしょうか?例えば、次のように書きます。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void CaluculateAll(System.Windows.Forms.ProgressBar progressBar)
    {
        progressBar.Maximum = 100000;
        progressBar.Step = 1;

        for(int j = 0; j < 100000; j++)
        {
            double pow = Math.Pow(j, j); //Calculation
            progressBar.PerformStep();
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        CaluculateAll(progressBar1);
    }
}

でも、そんなことはしたくない。

どうすればいい?

をご覧になることをお勧めします。 バックグラウンドワーカー . もしWinFormにそのような大きなループがあると、ブロックされてしまい、アプリがハングアップしたように見えてしまうのです。

見てください BackgroundWorker.ReportProgress() で、UIスレッドに進捗を報告する方法をご覧ください。

例えば

private void Calculate(int i)
{
    double pow = Math.Pow(i, i);
}

private void button1_Click(object sender, EventArgs e)
{
    progressBar1.Maximum = 100;
    progressBar1.Step = 1;
    progressBar1.Value = 0;
    backgroundWorker.RunWorkerAsync();
}

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    var backgroundWorker = sender as BackgroundWorker;
    for (int j = 0; j < 100000; j++)
    {
        Calculate(j);
        backgroundWorker.ReportProgress((j * 100) / 100000);
    }
}

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // TODO: do something with final calculation.
}