LoginSignup
2

More than 5 years have passed since last update.

PDCA支援ツールを作ろう その4 画面を作る その3 コントロールのEnableプロパティを状態マトリクスを利用して切り替える/プロパティを利用した状態遷移

Posted at

昨日我が家にOculus Goが届きましてね。ええ。

気がついたらこんな時間(午前4時)ですよ。
ひたすらゾンビ撃ってましたわ…

タイムマネジメントして、白鳥さん!

さて、そんなわけで今日はあんまり時間を割かずにサクッと作りこんで行きましょう。

PDCAサイクルの工程毎のラジオボタン/ボタンのEnable状態マトリクスを作成する

さて、前回と同じ様にサクッと状態マトリクスを作っていきましょう。

前回の状態マトリクスは機能もあいまってシンプルでしたが、
今回は工程によるボタンの状態変化を切り替えるので少し複雑になっています。

設計としては以下を仕様とします。

  • 到達していない工程のリッチテキストには切り替えられないようにする。
  • Planフェーズでのみ、継承ボタンを有効化する。
  • ケース未設定時、リッチテキスト・ボタンは全て変更不可とする。

以上のことを踏まえて作成した状態マトリクスがこちら

Caseの状態 RadioButton Plan RadioButton Do RadioButton Check RadioButton Act 継承ボタン 工程遷移ボタン リッチテキスト
Case未設定時 False False False False False False False
Planフェーズ False False False False True True True
Do フェーズ True True False False False True True
Check フェーズ True True False False True True True
Actフェーズ True True True True True False True

で、これを昨日と同様にコードに落とすと

Main.cs
        /* Status Table */
        private readonly bool[,] STATUS_TABLE_CONTROL_ENABLE = new bool[,]{
           /* RadioButtons              | Buttons               | RichTextBox              */
           /* Plan   Do     Check  Act  | Inhert.   N.Stage     | All                      */
            { false, false, false, false, false,    false,        false}, /* Case未設定時  */
            { false, false, false, false, true ,    true ,        true }, /* Case Plan時   */
            { true , true , false, false, false,    true ,        true }, /* Case Do時     */
            { true , true , true , false, false,    true ,        true }, /* Case Check時  */
            { true , true , true , true , false,    true ,        true }, /* Case Act時    */
        };

で、昨日と同様にアイテムに設定するための共通処理メソッドを作成する。

Main.cs

        /// <summary>
        /// コントロールのEnableプロパティを一括設定する。
        /// </summary>
        /// <param name="pStatus">Status</param>
        private void SetEnable(int pStatus) {

            rbtnPlan.Enabled        = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_RADIO_PLAN];
            rbtnDo.Enabled          = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_RADIO_DO];
            rbtnCheck.Enabled       = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_RADIO_CHECK];
            rbtnAct.Enabled         = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_RADIO_ACT];
            btnInheritance.Enabled  = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_BUTTON_INHERIT];
            btnNextStage.Enabled    = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_BUTTON_N_STAGE];
            rtbPlan.Enabled         = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_R_TEXT_ALL];
            rtbDo.Enabled           = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_R_TEXT_ALL];
            rtbCheck.Enabled        = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_R_TEXT_ALL];
            rtbAct.Enabled          = STATUS_TABLE_CONTROL_ENABLE[ pStatus, CTRL_R_TEXT_ALL];

            return;
        }

もしかしたら機能の時点で"似たような処理繰り返してるんだから繰り返しにすればよくね?"なんて思った方もいらっしゃるかもしれません。

結論から言えば、全然アリです。
たとえば機能の処理だと、処理の対象が全てSystem.Windows。Forms.RadioBoxなので、配列なりリストなりを作ってfor文なりforEach文なりを回してやれば記述は簡潔になります。

ただ、自分の出身が組込みだったせいもあって、どうしても気になっちゃうんですよ、処理の量が。
というのも、繰り返し文というのは繰り返しブロックの処理を回す度に判定を行うわけです。
今の時代、マシンパワーを持て余してるくらいなので、条件文でそこまで重くなることもあんま無いんですが
本当に細かいオーダーで考えるとどうしても上記のような、「少し冗長な」コードになる訳です。

一応理由というか、こだわりというか、そういう文化の下でこんなコード書いてたりします。

もし繰り返し文で書きたい場合、EnableプロパティはSystem.Windows.Forms.Controlというコントロールの大本から継承されているので
System.Windows.Forms.Controlの配列なりリストなり作ってfor文回してやると良いです。
記述はスマートになりますね。処理内容が微妙になりますが、そこはトレードオフです。
もしかしたらコンパイラが気を利かせていい感じにしてくれるかもしれません。

さて、状態の切り替えは基本的に次工程への遷移ボタンで行っていきます。
ここから切り替え処理を呼び出すようにしてもいいのですが、
せっかくなのでPropertyを使って実装しましょう。
あ、これは普通に使ったことあります。

プロパティを利用して処理をまとめる

さて、プロパティなんですが・・・

これ、結構初見のときに詰まった概念なんですよね。
当時の自分は「普通のメンバと何が違うってんだよ!」みたいな感じになってました。

で、詳細な説明を書いてくれてるサイトはたくさんあるんですが
初学者向けにわかりやすく一言で言いたい。(出来るとは言っていない)

と言うわけで、一言で言い表すのならこんな感じです。

『変数として扱える、セッター(変数に値を設定するための関数)とゲッター(変数の値を取得するための)のセット』

あくまで「変数として扱える」けど、「中身は関数(メソッド)」であることが伝わればいいかな、と。
擬似的にイベントのような使い方が出来るところがセクシーです。
さらにセッターとゲッターの片方だけを実装することも出来るってのもいいですね。
アクセス制限をかける方法としても利用が可能です

…毎回コード書くのに使った要素まとめて書いてるけど、ひとつひとつに分けて細かく書いた方が技術ブログっぽいのでは…?

さて、そんな素敵なプロパティ機能を利用して
状態が変化すると画面の状態遷移が連動するようにしたいと思います。

現在のステータスを表す値を取得/設定するプロパティを作ります。

結果がこちら。

Main.cs
        private int _currentStatus;

        (中略)

        private int currentStatus {
            get { return _currentStatus; }
            set {
                _currentStatus = value % STATUS_PROGRESS_NUM;
                SetEnable(_currentStatus);

                return;
            }

プロパティを利用して値を保持する際、受け皿として他の変数が必要になる点は注意してください。
もし用意せず、上のゲッターの中身を

         get { return currentStatus; }

なんてやると、普通にアプリが落ちます。
stackOverFlowってやつですね。
ちなみに
(プロパティ名){get; set;}
として記述した場合は別名の変数は不要です。
プロパティ名そのまま変数として利用できます。これはアクセスのr/w権限を制御するためのみの利用法ですね。

上記の処理を入れることで状態変更時の処理が非常に簡単になります。

と言うのも、初期化処理だろうが状態遷移時の処理だろうが
currentStatusに適切なステータスの値を入れるだけでOKになるんですね。
もちろん他の処理によるキレイな実装もいろいろあるんですが(ファンクションポインタ/デリゲート配列を利用するとか)、
今回はこちらで実装していきます。

さて、後は次工程に移るための次工程ボタン(NextStage)ボタンのクリックイベントを実装して動作を確認していきましょう。

Planフェーズ:
2018y06m08d_060441308.jpg

Doフェーズ:
2018y06m08d_060526494.jpg

Checkフェーズ:
2018y06m08d_060528878.jpg

Actフェーズ:
2018y06m08d_060531511.jpg

Case未設定時:
2018y06m08d_060534545.jpg

後はデータの保存と呼び出し処理を実装すれば完成ですね。
ってことは本日はここまで。

今日はほとんど記事の更新に費やしてしまった・・・
所要時間は01:21:17でした。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2