プログラム初心者勉強会　9回目　プログレスバーの実装　-C# Windowsフォーム入門

#目次
[1. 前回リンク](#1-前回リンク)
[2. 次回リンク](#2-次回リンク)
[3. やったこと](#3-やったこと)
[4. 配信時の録画](#4-配信時の録画)
[5. 今回学んだこと](#5-今回学んだこと)
[6. プログレスバーの動作確認](#6-プログレスバーの動作確認)
[7. ダイアログ上でプログレスバーを動かす](#7-ダイアログ上でプログレスバーを動かす)
[8. 各イベントの順番について](#8-各イベントの順番について)
[9. 振り返り](#9-振り返り)
[10. 次回予告](#10-次回予告)

#1. 前回リンク
https://qiita.com/Usyuuu-program-beginner/items/7e3f3ada4750cb3adff5

#2. 次回リンク
https://qiita.com/Usyuuu-program-beginner/items/53f16b206009da19ddd7

#3. やったこと
プログレスバーの実装を学んだよ

〇　ステータスバーにプログレスバーを表示させるやりかた

https://uchukamen.com/Programming1/StatusBar/index.htm

〇　プログレスバーをダイアログに表示させるやりかた

・　Tickイベント

https://www.ipentec.com/document/csharp-using-timer-control

#4. 配信時の録画
https://www.youtube.com/watch?v=AA0SawSk1ZQ

#5. 今回学んだこと
プログレスバーの設置がこんなに簡単な事、そして制御がこんなにややこしいことを初めて知った。勉強してよかった

#6. プログレスバーの動作確認
#6.1 ツールバーにプログレスバーを表示させる場合
　1. デザイン画面に「toolStrip」をDrag＆Dropする
　2. 配置したtoolStripを「ProgressBar」に設定する
　3. 後はProgressBar化したtoolStripのプロパティ「value」「Minimum」「Maximum」を編集して、プログレスバーを自由に動かす

#6.2 プログレスバーを画面にそのまま配置する
　1. デザイン画面に「ProgressBar」をDrag＆Dropする
　2. 後はProgressBarのプロパティ「value」「Minimum」「Maximum」を編集して、プログレスバーを自由に動かす

#6.3 プログレスバーの動作確認
　1. Minimum=0、Maximum=100、value=0とする
　2. デザイン画面にボタンを1つ配置し、そのボタンが押されるたびにvalueが10加算されるようにする
　3. ボタンを押した分プログレスバーが進むことを確認する
　**注意：**　Maxよりもvalue値が大きくなるとエラーになる。

```C#:　ボタンを押すごとにプログレスバーが進むボタンイベントハンドラ関数
private void button1_Click(object sender, EventArgs e)
{
    // valueがMaxの100に到達したら0に戻る
    if(this.toolStripProgressBar1.Value == 100)
    {
        this.toolStripProgressBar1.Value = 0;
    }
    else
    {
        this.toolStripProgressBar1.Value += 10;
    }
}
```
[4. 配信時の録画](#4-配信時の録画)の配信動画リンク、25:25から観ればボタンの挙動が分かります。

#7. ダイアログ上でプログレスバーを動かす
##7.1 やりたいこと
フォーム画面に配置されたボタン(Button2)を押す　→　ダイアログが表示される　→　表示されたダイアログ上でプログレスバーが自動で進む

実装するプログレスバーは、Max値が100で、1秒間にValue+=10する。

実現方法にはモーダルダイアログを開く場合、モーダレスダイアログを開く場合で方法が分かれる。
今回はモーダレスダイアログを使用した場合を記載する。

###7.2 モーダレスダイアログ上にプログレスバーを配置する
###7.2.1　Thread.Sleepを使用して1秒ごとの処理を実施する場合

<font color="red">7.2.2章記載のTickイベントを使う方が絶対に良いです。こちらは参考程度に読んでください。</span>

プログレスバーの動作と、Form画面上の動作を非同期にすることで、ダイアログを開いた直後からプログレスバーの処理を実施できる。

```C#:　Form画面用コード（Form1.cs）
using System
using System.Windows.Forms;

namespace MenuStudy2
{
    public partial class Form1 : Form
    {
        // ...省略

        private void button2_Click(object sender, EventArgs e)
        {
                DialogTest Dialog = new DialogTest();
                Dialog.Owner = this;
                Dialog.Show();
                Dialog.ProgressBareMove(); 
        }
    }

    // ...省略
```
```C#:　モーダレスダイアログ用コード（DiagTest.cs）
using System
using System.Windows.Forms;
using System.Threading;

namespace DialogTest_Progress
{
    public partial class DialogTest : Form
    {
    	// ...省略
		
		//プログレスバーを1秒に10進める関数
		public void ProgressBarMove()
		{
			for(int timer=0;timer<10;timer++)
			{
			    // valueがMaxの100に到達したら0に戻る
			    if(this.toolStripProgressBar1.Value == 100)
			    {
			        this.toolStripProgressBar1.Value = 0;
			    }
			    else
			    {
			        this.toolStripProgressBar1.Value += 10;
			    }
			    Thread.Sleep(1000);
			}
		}
    // ...省略
```

もしモーダルダイアログでこの内容のコードを動かすと、バーがうまく動いてくれないよ。
※　[4. 配信時の録画](#4-配信時の録画)の配信動画リンク、57:35から観れば失敗時の挙動が分かります。
※　[4. 配信時の録画](#4-配信時の録画)の配信動画リンク、01:12:20から観れば成功時の挙動が分かります。

このようにうまく動作しましたが、1点ダメなところがあります。それは「キャンセルボタンを実装できない」ことです。
Thread.Sleep処理時はスレッド処理がすべて停止します。今回モーダレスダイアログの処理がForループする度に1秒間停止する為、ボタンを配置しても画面上に反映される時間が極端に短くなります。
そして、人がボタンを押すことが実質不可能となります。

※　[4. 配信時の録画](#4-配信時の録画)の配信動画リンク、01:34:45から観れば失敗時の挙動が分かります。

そのため、繰り返しの動作を行わせる場合は、7.2.2章のTickイベントを使用すべきです。

##7.3　モーダルダイアログ上にプログレスバーを配置する場合（Tickイベントを使用した場合）

　1. Timer.Tickイベントを使用し、1秒間ごとにプログレスバーを移動させる。
     デザイン画面で「Timer」をDrag＆Dropし、Intervalプロパティを1000にする。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2130837/a3215c9b-9b1e-c2ea-0132-b4e3b40e0ac1.png)

　2. モーダルダイアログ上のShowイベント登録用関数内でTimerを開始させる。
　3. Tickイベント用ハンドラ関数内で、プログレスバーを進める処理を記載
　4. キャンセルボタンも実装し、キャンセルボタンを押せばダイアログが閉じるようにする

```C#:　モーダレスダイアログ用コード（DiagTest.cs）
namespace DialogTest_Progress
{
    public partial class DialogTest : Form
    {
        
        public DialogTest()
        {
            InitializeComponent(); 
        }

        // shownイベント用ハンドラ関数
        private void DialogTest_Shown_1(object sender, EventArgs e)
        {
            //タイマー開始
            timer1.Enabled = true;
        }
        
        // Tickイベント用ハンドラ関数
        private void DialogTest_Shown(object sender, EventArgs e)
        {
            if (this.progressBar1.Value == 100)
            {
                this.progressBar1.Value = 0;
            }
            else
            {
                this.progressBar1.Value += 10;
            }
        }

        //キャンセルボタンのクリックイベントハンドラ関数
        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }
```

```C#:　Form画面用コード（Form1.cs）
using System;
using System.Windows.Forms;
using DialogTest_Progress;

namespace MenuStudy2
{
    public partial class Form1 : Form
    {
        // ...省略

        private void button2_Click(object sender, EventArgs e)
        {
            DialogTest Dialog = new DialogTest();
            Dialog.Owner = this;
            Dialog.Show();
        }
}
```

※　[4. 配信時の録画](#4-配信時の録画)の配信動画リンク、02:07:55から観れば成功時の挙動が分かります。

#8. 各イベントの順番について

次に記載する記事が詳しく解説してくれていた。「Load」イベントよりも早く処理されるイベントがあるんだなとビックリしましたね

https://qiita.com/entan05/items/52b35c18170233993c1f

#9. 振り返り
プログレスバーの挙動実装はかなりハードル高いと思い込んでたので、こんなに簡単に実装出来る事にびっくりしたよ

#10. 次回予告
次回は12月5日(日）の20時からやるよ。
次どこを勉強するかは考えておくね

##ニコニコ配信先
https://com.nicovideo.jp/community/co3601066

##Twitch配信先
https://www.twitch.tv/programing_study_meeting

##Discordリンク
https://discord.gg/7rcqhMGpvA