1

プログラムの UI を作成していますが、変換ボタンをクリックした後にプログレス バーが表示されない理由がわかりません。

private void convertButton_Click(object sender, EventArgs e)
{
    toolStripProgressBar.Visible = true;

    ...

    toolStripProgressBar.Visible = false;
}

Python の tkinter で同様の問題に遭遇し、関数を呼び出してアイドル タスクを更新する必要がありました。スレッドを使用せずに Windows フォームでこれを行う方法はありますか?

編集:補足として、これはステータスバーのテキストで更新されるラベルも含むtoolStripの進行状況バーです。左側にラベルを並べて表示するのではなく、左側に進行状況バーを表示する方法はありますか?

4

7 に答える 7

4

スレッドを使用せずにこれを行う方法があります ( )Application.DoEvents、使用しないことを強くお勧めします。再入可能性は厄介であり、UI スレッドがまったく拘束されることは望ましくありません。

代わりに使用してくださいBackgroundWorker- 簡単で、進行状況バー用に設計されています。別のスレッドを使用して進行状況を UI スレッドに報告する手間が省けます。Control.Invokeetcは必要ありません。

たくさんのチュートリアルBackgroundWorkerがあります- 使いこなすのにそれほど時間はかかりません.

于 2009-04-02T19:33:11.667 に答える
2

スレッドなしでこれを行う方法について尋ねた質問によると、それは Application.DoEvents(); で行うことです。(進行状況バーを表示可能に設定した直後にその呼び出しを追加するだけです。)

今、私は Jon Skeet に同意しますが、BackgroundWorker はこれを行うためのより良い方法ですが、別のスレッドを使用します。

于 2009-04-02T19:33:42.323 に答える
1

UI スレッドとは別のスレッドでプロセスを実行し、その進行状況を定期的に UI スレッドに報告する必要があります。変換操作が UI スレッド内で動作している場合、操作が完了するまで応答しなくなります。

于 2009-04-02T19:33:49.187 に答える
1

問題は"..."、コード内の が長時間実行されるプロセスであることだと思います。UI の更新は瞬時に行われるわけではありませんが、ウィンドウのメッセージ キューを通過してから画面に描画される必要があります。キューがポンプされ、イベントと同じスレッドで描画が行われます。

その結果、実行時間の長いタスクは別のスレッドに移動する必要があります。それ以上に、そのスレッドが終了した後にコードの行行を呼び出す必要があります。それ以外の場合は、進行状況バーを設定し、すぐに再びオフにします。

これを行う 1 つの方法は、BackgroundWorker コントロールを使用することです。

于 2009-04-02T19:34:24.240 に答える
1

進行状況バーは、メッセージの処理中に発生するペイントが許可されている場合にのみ表示されます。通常、イベント ハンドラーの実行中はメッセージ処理を実行できません。プログレス バーを表示するには、可視性を true に設定し、バックグラウンド スレッドを開始して作業を完了し、ハンドラーから戻る必要があります。

于 2009-04-02T19:35:26.983 に答える
1

物事がどのように機能するかを説明しようとする2つのリンクを次に示します。 (1) (2)

それでは、できる限り手短に説明しようと思います。Windows フォーム アプリケーション内で発生することのほとんどは、単一のスレッドで発生します。通常、同じスレッドで Main() が実行されます。Program.cs を開くと、Main() に次のような行があることがわかります。

Application.Run(new Form1());

いつでもアプリケーションをデバッグしてコール スタックを調べると、その Run メソッドまでトレース バックすることがわかります。これは、Windows フォーム アプリケーションが実際には Run メソッドの継続的な実行であることを意味します。それで、ランは何をしているのですか?Run は、Windows がメッセージを送信するメッセージ キューを消費しています。Run は、それらのメッセージを正しいコントロールにディスパッチします。コントロールは、押されたキーに対応するテキストを追加したり、自分自身を再描画したりするなどのことを行います。これはすべて、単一のスレッドと一緒に無限ループが実行されている間に発生することに注意してください。または単にウィンドウを移動すると、それらのメッセージの負荷がアプリケーションに渡され、アプリケーションはそれらを処理し、それに応じて反応します。すべてその単一のスレッドで行われます。コントロールは、キューを介して自分自身にメッセージを送信することもできます。また、Control.BeginInvoke を介してポンプにメッセージを配置することもできます。これらのコントロールが行うことの 1 つは、何が起こるかに応じてイベントを発生させることです。したがって、ボタンをクリックすると、そのクリックを処理するために記述したコードが、Application.Run メソッドによって最終的かつ間接的に実行されます。

ここで、コードで何が起こっているかというと、プログレス バーの表示ステータスを表示に変更してからその値を更新しているにもかかわらず、すべて同じメソッドでその表示を false に変更しているということです。これは、メソッドを終了した後にのみ、Application.Run() がメッセージ キューの繰り返しと消費を継続できることを意味し、プログレス バーにその表示を更新するよう効果的に要求します。その場合、メソッドを終了する前に行った最後の処理である、進行状況バーの可視性を既に false のままにしています。DoEvents() は、キュー内のメッセージを読み取って処理するため、問題に対する迅速で汚い回避策です。再入可能性の問題が発生する可能性があるため、使用するのはあまり快適ではありません。

スレッドを使用することは良い解決策ですが、この種の状況ではカスタム スレッドの代わりに ThreadPool スレッドを使用することをお勧めします。それらのライフサイクルを制御します。スレッドを使用する最も簡単で実用的な方法は、BackgroundWorker コンポーネントを使用することですが、何が起こっているのかを本当に理解したい場合は、デリゲートを使用して Windows フォームのマルチスレッドを実行する方法を理解するのに苦労することをお勧めします。

于 2009-04-02T20:39:59.230 に答える