いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

進捗状況ダイアログ (処理中ダイアログ, 進行状況ダイアログ, Form, Thread, ProgressBar)

画面開発にて、よく進捗状況を表示するためのダイアログを作成することが
よくあります。


その際、いつも参考にしているリソースです。
よく忘れるのでメモメモ。


以下のリンクの中でも特にdobonさんのページの内容が一番
わかりやすく、実用的です。(感謝)


要は、別のスレッドでフォームをモーダルで起動するのがポイントなのですが
結構いろいろなカスタマイズを考えると作るのが難しい場合もままあり。


すご〜く適当なサンプルですが、こんな感じ。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Reflection;
using System.Runtime.Remoting;
using System.Threading;
using System.Windows.Forms;

namespace Gsf.Samples{

    public class SampleLauncher{

        static void Main(string[] args){

            string className = typeof(Dummy).Name;
            if(args.Length != 0){
                className = args[0];
            }

            if(!string.IsNullOrEmpty(className)){
                className = string.Format("{0}.{1}", typeof(SampleLauncher).Namespace, className);
            }

            Assembly     assembly = Assembly.GetExecutingAssembly();
            ObjectHandle handle   = Activator.CreateInstance(assembly.FullName, className);
            if(handle != null){
                object clazz = handle.Unwrap();

                if(clazz != null){
                    (clazz as IExecutable).Execute();
                }
            }
        }
    }

#region "共通インターフェース定義"
    interface IExecutable{
        void Execute();
    }
#endregion

#region "進行状況ダイアログのサンプル"
    class ProgressDialogSample : IExecutable{

        private class Dialog : Form{

            public Dialog(){
                InitializeComponent();
            }

            protected void InitializeComponent(){
                SuspendLayout();

                Text          = "処理中・・・・・";
                Size          = new Size(100, 100);
                TopMost       = true;
                ControlBox    = false;
                MaximizeBox   = false;
                MinimizeBox   = false;
                ShowIcon      = false;
                ShowInTaskbar = false;

                ResumeLayout();
            }
        }

        private class ThreadInfo{
            public Form Owner{
                get;
                set;
            }

            public Form Dialog{
                get;
                set;
            }

            public ManualResetEvent WaitHandle{
                get;
                set;
            }
        }

        private class ParentForm : Form{

            public ParentForm(){
                InitializeComponent();
            }

            protected void InitializeComponent(){
                SuspendLayout();

                Text = "親フォーム";
                Size = new Size(500, 500);

                Button btnShowDialog = new Button();
                btnShowDialog.Text   = "ダイアログ表示";
                btnShowDialog.Width  = 100;
                btnShowDialog.Dock   = DockStyle.Fill;
                btnShowDialog.Click += (s, e) => {

                    Enabled = false;

                    ThreadInfo info   = new ThreadInfo{Owner = this, WaitHandle = new ManualResetEvent(false)};
                    Thread     thread = new Thread((val) => {
                        ThreadInfo tinfo = val as ThreadInfo;
                        Form       owner = tinfo.Owner;

                        Dialog dialog = new Dialog();

                        dialog.StartPosition = FormStartPosition.Manual;
                        dialog.Left          = owner.Left + (owner.Width  - dialog.Width)  / 2;
                        dialog.Top           = owner.Top  + (owner.Height - dialog.Height) / 2;

                        dialog.Activated    += (s2, e2) => {
                            tinfo.WaitHandle.Set();
                        };

                        tinfo.Dialog = dialog;

                        dialog.ShowDialog();
                    });

                    thread.IsBackground = true;
                    thread.Start(info);

                    info.WaitHandle.WaitOne();

                    for(int i = 0; i < 10; i++){
                        string caption = string.Format("{0}%完了", ((i + 1) * 10));
                        info.Dialog.Invoke(new MethodInvoker(() => {
                            info.Dialog.Text = caption;
                        }));
                        
                        Thread.Sleep(1000);
                    }

                    info.Dialog.Invoke(new MethodInvoker(info.Dialog.Close));

                    Enabled = true;
                    Activate();

                };

                Controls.Add(btnShowDialog);

                ResumeLayout();
            }
        }

        [STAThread]
        public void Execute(){
            Application.Run(new ParentForm());
        }
    }
#endregion
}


実務で利用する場合は、ダイアログの管理を行なうクラスを作成し、それを経由して
ダイアログの操作を行なうようにしたりします。



================================
過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。