DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

DOBON.NET

スプラッシュウィンドウを表示する

「スプラッシュウィンドウ(Splash Window)」とは、アプリケーション起動時に真っ先に表示され、アプリケーションのロゴやバージョンなどの情報を表示し、自動的に消える(消えないものも稀にありますが)ウィンドウです。Microsoft Visual Studioや、Officeなど、多くのアプリケーションでスプラッシュウィンドウが使われています。

なお、Visual Studio 2005以降のVB.NETをお使いであれば、もっと簡単な方法があります。この方法に関しては、「VB.NETでスプラッシュウィンドウを表示する」をご覧ください。

スプラッシュウィンドウに必要な機能

まず、スプラッシュウィンドウに絶対必要な機能をあげてみます。

  1. メインウィンドウより先に表示される。
  2. 画面中央に表示される。
  3. ウィンドウにタイトルバーや枠が無い。
  4. アプリケーションの準備ができたところで、自動的に閉じる。

1.に関しては、エントリポイント(Mainメソッド)または、メインフォームのコンストラクタやLoadイベントハンドラなどでメインフォームが表示される前にスプラッシュウィンドウを表示するようにすればよいでしょう。2.に関してはスプラッシュウィンドウのフォームのStartPositionプロパティをCenterScreenに、3.に関してはFormBorderStyleプロパティをNoneにすればよいでしょう。

問題は4.です。どのタイミングでスプラッシュウィンドウを閉じるべきでしょうか?メインフォームが表示されるタイミングでということであれば、メインフォームのActivatedイベントで閉じるようにすればよいでしょう。また、「アプリケーションの準備ができた」ということを「アプリケーションがアイドル状態になった時」と解釈すると、Application.Idleイベントで閉じる方法も考えられます。さらに、メインフォームのLoadイベントハンドラの最後で閉じる方法もあります。起動してから指定時間までスプラッシュウィンドウを表示したいときは、タイマーを使う方法もあるかもしれません(個人的な意見としては、スプラッシュウィンドウは用が無くなったらさっさと閉じるべきだと思いますので、この方法はお勧めしたくありません)。

以上の機能以外に、場合によっては、次のような機能も必要になるでしょう。

  1. タスクバーに表示しない。(スプラッシュウィンドウがタスクバーに表示されるアプリも多いです。)
  2. メインウィンドウより手前に表示される。

5.については、フォームのShowInTaskbarプロパティをFalseにすればよいでしょう。6.については、フォームのTopMostプロパティをTrueにする方法があります。しかし、個人的な意見としては、TopMostにはせずに、メインウィンドウの後ろに隠れないようにAddOwnedFormメソッド等を使用するにとどめた方がよいと思います。

スプラッシュウィンドウ作成の実際

以上のことを踏まえ、実際にスプラッシュウィンドウを作ってみます。

まずプロジェクトに新しいフォームを追加し、名前を「SplashForm」とします。SplashFormのStartPositionプロパティをCenterScreen、FormBorderStyleプロパティをNone、さらにShowInTaskbarプロパティをFalseにします。その他、画像の配置など、SplashFormのデザインを適当に行ってください。

さらにSplashFormクラスに次のようなコードを記述します。ここではApplication.IdleイベントでSplashFormを閉じることにします。

[VB.NET]
'Splashフォーム
Private Shared _form As SplashForm = Nothing

''' <summary>
''' Splashフォーム
''' </summary>
Public Shared ReadOnly Property Form() As SplashForm
    Get
        Return _form
    End Get
End Property

''' <summary>
''' Splashフォームを表示する
''' </summary>
Public Shared Sub ShowSplash()
    If _form Is Nothing Then
        'Application.IdleイベントハンドラでSplashフォームを閉じる
        AddHandler Application.Idle, AddressOf Application_Idle
        'Splashフォームを表示する
        _form = New SplashForm
        _form.Show()
    End If
End Sub

'アプリケーションがアイドル状態になった時
Private Shared Sub Application_Idle( _
        ByVal sender As Object, ByVal e As EventArgs)
    'Splashフォームがあるか調べる
    If Not (_form Is Nothing) And _form.IsDisposed = False Then
        'Splashフォームを閉じる
        _form.Close()
    End If
    _form = Nothing
    'Application.Idleイベントハンドラの削除
    RemoveHandler Application.Idle, AddressOf Application_Idle
End Sub
[C#]
//Splashフォーム
private static SplashForm _form = null;

/// <summary>
/// Splashフォーム
/// </summary>
public static SplashForm Form
{
    get { return _form; }
}

/// <summary>
/// Splashフォームを表示する
/// </summary>
public static void ShowSplash()
{
    if (_form == null)
    {
        //Application.IdleイベントハンドラでSplashフォームを閉じる
        Application.Idle += new EventHandler(Application_Idle);
        //Splashフォームを表示する
        _form = new SplashForm();
        _form.Show();
    }
}

//アプリケーションがアイドル状態になった時
private static void Application_Idle(object sender, EventArgs e)
{
    //Splashフォームがあるか調べる
    if (_form != null && _form.IsDisposed == false)
    {
        //Splashフォームを閉じる
        _form.Close();
    }
    _form = null;
    //Application.Idleイベントハンドラの削除
    Application.Idle -= new EventHandler(Application_Idle);
}

SplashFormを表示するには、SplashForm.ShowSplashメソッドを呼び出します。次の例では、エントリポイントであるMainメソッドでメインフォームForm1を表示させる前にスプラッシュウィンドウを表示させています。エントリポイントの意味が分からなければ、まずこちらをご覧ください。

[VB.NET]
<STAThread()> _
Shared Sub Main()
    'スプラッシュウィンドウを表示
    SplashForm.ShowSplash()

    'メインウィンドウを表示
    Application.Run(New Form1)
End Sub
[C#]
[STAThread]
static void Main() 
{
    //スプラッシュウィンドウを表示
    SplashForm.ShowSplash();
    
    //メインウィンドウを表示
    Application.Run(new Form1());
}

スプラッシュウィンドウを別スレッドで表示する

次にスプラッシュウィンドウをメインスレッドとは別のスレッドで表示させるようにしてみます。

まず、スプラッシュウィンドウのフォームクラスは先の例と同様の方法で作成しておき(ここでもクラスの名前を"SplashForm"とします)、SplashFormクラス内に次のようなコードを記述してください。

[VB.NET]
'Splashフォーム
Private Shared _form As SplashForm = Nothing
'メインフォーム
Private Shared _mainForm As Form = Nothing
'Splashを表示するスレッド
Private Shared _thread As System.Threading.Thread = Nothing
'lock用のオブジェクト
Private Shared ReadOnly syncObject As New Object

''' <summary>
''' Splashフォーム
''' </summary>
Public Shared ReadOnly Property Form() As SplashForm
    Get
        Return _form
    End Get
End Property

''' <summary>
''' Splashフォームを表示する
''' </summary>
''' <param name="mainForm">メインフォーム</param>
Public Shared Sub ShowSplash(ByVal mainForm As Form)
    If Not (_form Is Nothing) Or Not (_thread Is Nothing) Then
        Return
    End If

    _mainForm = mainForm
    'メインフォームのActivatedイベントでSplashフォームを消す
    If Not (_mainForm Is Nothing) Then
        AddHandler _mainForm.Activated, _
            AddressOf _mainForm_Activated
    End If

    'スレッドの作成
    _thread = New System.Threading.Thread( _
        New System.Threading.ThreadStart(AddressOf StartThread))
    _thread.Name = "SplashForm"
    _thread.IsBackground = True
    _thread.ApartmentState = System.Threading.ApartmentState.STA
    'スレッドの開始
    _thread.Start()
End Sub

''' <summary>
''' Splashフォームを表示する
''' </summary>
Public Shared Sub ShowSplash()
    ShowSplash(Nothing)
End Sub

''' <summary>
''' Splashフォームを消す
''' </summary>
Public Shared Sub CloseSplash()
    SyncLock (syncObject)
        If Not (_form Is Nothing) And _form.IsDisposed = False Then
            'Splashフォームを閉じる
            'Invokeが必要か調べる
            If _form.InvokeRequired Then
                _form.Invoke(New MethodInvoker(AddressOf _form.Close))
            Else
                _form.Close()
            End If
        End If
        If Not (_mainForm Is Nothing) Then
            RemoveHandler _mainForm.Activated, _
                AddressOf _mainForm_Activated
            'メインフォームをアクティブにする
            _mainForm.Activate()
        End If

        _form = Nothing
        _thread = Nothing
        _mainForm = Nothing
    End SyncLock
End Sub

'スレッドで開始するメソッド
Private Shared Sub StartThread()
    'Splashフォームを作成
    _form = New SplashForm
    'Splashフォームをクリックして閉じられるようにする
    AddHandler _form.Click, AddressOf _form_Click
    'Splashフォームを表示する
    Application.Run(_form)
End Sub

'Splashフォームがクリックされた時
Private Shared Sub _form_Click( _
        ByVal sender As Object, ByVal e As EventArgs)
    'Splashフォームを閉じる
    CloseSplash()
End Sub

'メインフォームがアクティブになった時
Private Shared Sub _mainForm_Activated( _
        ByVal sender As Object, ByVal e As EventArgs)
    'Splashフォームを閉じる
    CloseSplash()
End Sub
[C#]
//Splashフォーム
private static SplashForm _form = null;
//メインフォーム
private static Form _mainForm = null;
//Splashを表示するスレッド
private static System.Threading.Thread _thread = null;
//lock用のオブジェクト
private static readonly object syncObject = new object();

/// <summary>
/// Splashフォーム
/// </summary>
public static SplashForm Form
{
    get { return _form; }
}

/// <summary>
/// Splashフォームを表示する
/// </summary>
/// <param name="mainForm">メインフォーム</param>
public static void ShowSplash(Form mainForm)
{
    if (_form != null || _thread != null)
        return;

    _mainForm = mainForm;
    //メインフォームのActivatedイベントでSplashフォームを消す
    if (_mainForm != null)
    {
        _mainForm.Activated += new EventHandler(_mainForm_Activated);
    }

    //スレッドの作成
    _thread = new System.Threading.Thread(
        new System.Threading.ThreadStart(StartThread));
    _thread.Name = "SplashForm";
    _thread.IsBackground = true;
    _thread.ApartmentState = System.Threading.ApartmentState.STA;
    //スレッドの開始
    _thread.Start();
}

/// <summary>
/// Splashフォームを表示する
/// </summary>
public static void ShowSplash()
{
    ShowSplash(null);
}

/// <summary>
/// Splashフォームを消す
/// </summary>
public static void CloseSplash()
{
    lock (syncObject)
    {
        if (_form != null && _form.IsDisposed == false)
        {
            //Splashフォームを閉じる
            //Invokeが必要か調べる
            if (_form.InvokeRequired)
                _form.Invoke(new MethodInvoker(_form.Close));
            else
                _form.Close();
        }

        if (_mainForm != null)
        {
            _mainForm.Activated -= new EventHandler(_mainForm_Activated);
            //メインフォームをアクティブにする
            _mainForm.Activate();
        }

        _form = null;
        _thread = null;
        _mainForm = null;
    }
}

//スレッドで開始するメソッド
private static void StartThread()
{
    //Splashフォームを作成
    _form = new SplashForm();
    //Splashフォームをクリックして閉じられるようにする
    _form.Click += new EventHandler(_form_Click);
    //Splashフォームを表示する
    Application.Run(_form);
}

//Splashフォームがクリックされた時
private static void _form_Click(object sender, EventArgs e)
{
    //Splashフォームを閉じる
    CloseSplash();
}

//メインフォームがアクティブになった時
private static void _mainForm_Activated(object sender, EventArgs e)
{
    //Splashフォームを閉じる
    CloseSplash();
}

前のようにApplication.Idleイベントでスプラッシュウィンドウを閉じると、スプラッシュウィンドウは表示されたと思うと、あっという間に閉じてしまいますので、別のタイミングで閉じるようにします。ここでは、メインフォームのActivatedイベントで閉じています。(さらにSplashFormのClickイベントでもSplashFormを閉じるようにしています。)

SplashFormを表示するには、前と同様、SplashForm.ShowSplashメソッドを呼び出しますが、このときメインフォームのインスタンスを指定できます。メインフォームを指定すると、そのActivatedイベントハンドラで自動的にSplashFormが閉じられます。メインフォームを指定しなかった時は、適当な位置(メインウィンドウのActivatedイベントハンドラなど)でSplashForm.CloseSplashメソッドを呼び出してSplashFormを閉じてください。

上のコードを使ってスプラッシュウィンドウを表示させるコードを以下に示します。ここでも、エントリポイントであるMainメソッドでメインフォームForm1を表示させる前にスプラッシュウィンドウを表示させています。

[VB.NET]
<STAThread()> _
Shared Sub Main()
    Dim mainForm As New Form1

    'スプラッシュウィンドウを表示
    SplashForm.ShowSplash(mainForm)

    'メインウィンドウを表示
    Application.Run(mainForm)
End Sub
[C#]
[STAThread]
static void Main() 
{
    Form1 mainForm = new Form1();

    //スプラッシュウィンドウを表示
    SplashForm.ShowSplash(mainForm);
    
    //メインウィンドウを表示
    Application.Run(mainForm);
}

補足:スプラッシュウィンドウは、アプリケーションが起動してから準備ができるまでに長い時間がかかる時に、ユーザーを不安にさせたり、待たせたりしないために表示するというのが主要な使用目的でしょう。そのため、起動にそれほど時間のかからないアプリではスプラッシュウィンドウは必要ありません。ユーザーの立場からすると、無駄なスプラッシュウィンドウにはうんざりさせられます。

  • 履歴:
  • 05/9/23 マルチスレッドによるサンプルを修正しました。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。