いろいろ備忘録日記

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

フォームの表示と非表示の際の挙動を変化させる。(AnimateWindow, Win32, InteropServices, WinForms, user32.dll)


今回は、ちょっとした小ネタです。


フォームを表示する際、非表示にする際
通常は、いつも見る挙動をします。


その挙動をちょっとカスタマイズしてみようという話です。
挙動をカスタマイズするには、標準の.NETのライブラリでは
不可能で、Win32 APIを利用します。


以下のAPIを利用します。

        [DllImport("user32")]
        static extern bool AnimateWindow(IntPtr hwnd, int time, uint flags);


上記のAnimateWindow関数の3つ目の引数にいろいろなパターンの値を設定する事で
挙動をカスタマイズできます。


以下、サンプルです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication1
{
    /// <summary>
    /// AnimateWindow関数にて利用されるフラグを表す列挙型です。
    /// </summary>
    [Flags]
    public enum AnimateWindowFlags : uint
    {
        AW_HOR_POSITIVE = 0x00000001,
        AW_HOR_NEGATIVE = 0x00000002,
        AW_VER_POSITIVE = 0x00000004,
        AW_VER_NEGATIVE = 0x00000008,
        AW_CENTER       = 0x00000010,
        AW_HIDE         = 0x00010000,
        AW_ACTIVATE     = 0x00020000,
        AW_SLIDE        = 0x00040000,
        AW_BLEND        = 0x00080000
    }

    public partial class Form1 : Form
    {
 
        /// <summary>
        /// AnimateWindow関数
        /// </summary>
        /// <param name="hwnd">ハンドル</param>
        /// <param name="time">アニメーションを行う時間</param>
        /// <param name="flags">挙動を表すフラグ</param>
        [DllImport("user32")]
        static extern bool AnimateWindow(IntPtr hwnd, int time, uint flags);

        public Form1()
        {
            InitializeComponent();
        }

        private void btnSlide_Click(object sender, EventArgs e)
        {
            //
            // 以下のアニメーションを行いながら、新たなフォームを表示する.
            //
            // ■アニメーションの方向:横方向
            // ■アニメーションの種類:スライド
            //
            Form1 newForm = new Form1();
            AnimateWindow(newForm.Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_SLIDE));
            newForm.Show();
        }

        private void btnFadein_Click(object sender, EventArgs e)
        {
            //
            // 以下のアニメーションを行いながら、新たなフォームを表示する.
            //
            // ■アニメーションの方向:横方向
            // ■アニメーションの種類:フェードイン
            //
            Form1 newForm = new Form1();
            AnimateWindow(newForm.Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_BLEND));
            newForm.Show();
        }

        private void btnCenter_Click(object sender, EventArgs e)
        {
            //
            // 以下のアニメーションを行いながら、新たなフォームを表示する.
            //
            // ■アニメーションの方向:横方向
            // ■アニメーションの種類:中央から徐々に表示
            //
            Form1 newForm = new Form1();
            AnimateWindow(newForm.Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_CENTER));
            newForm.Show();
        }

        private void btnSlideHide_Click(object sender, EventArgs e)
        {
            //
            // 以下のアニメーションを行いながら、自分自身を非表示→再表示する.
            //
            // ■アニメーションの方向:横方向
            // ■アニメーションの種類:スライド
            //
            AnimateWindow(Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_SLIDE | AnimateWindowFlags.AW_HIDE));
            Hide();
            
            Application.DoEvents();

            Thread.Sleep(TimeSpan.FromSeconds(1.0));

            AnimateWindow(Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_SLIDE));
            Show();
        }

        private void btnFadeinHide_Click(object sender, EventArgs e)
        {
            //
            // 以下のアニメーションを行いながら、自分自身を非表示→再表示する.
            //
            // ■アニメーションの方向:横方向
            // ■アニメーションの種類:フェードイン
            //
            AnimateWindow(Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_BLEND | AnimateWindowFlags.AW_HIDE));
            Hide();

            Application.DoEvents();

            Thread.Sleep(TimeSpan.FromSeconds(1.0));

            AnimateWindow(Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_BLEND));
            Show();
        }

        private void btnCenterHide_Click(object sender, EventArgs e)
        {
            //
            // 以下のアニメーションを行いながら、自分自身を非表示→再表示する.
            //
            // ■アニメーションの方向:横方向
            // ■アニメーションの種類:中央から徐々に
            //
            AnimateWindow(Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_CENTER | AnimateWindowFlags.AW_HIDE));
            Hide();

            Application.DoEvents();

            Thread.Sleep(TimeSpan.FromSeconds(1.0));

            AnimateWindow(Handle, 1000, (uint) (AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_CENTER));
            Show();
        }
    }
}


AnimateWindow関数は、ShowまたはHideする前に、実行する必要があります。
また、関数の引数のflagsには、直接uint値を設定することも出来ますが
出来る限り、上記のようにEnumを定義して利用する方がいいです。


[参考資料]


上記のサンプルをアップしておきました。
どんな風な動きになるのか興味がある方は、どうぞ。


(補足) すみません。サンプルをVS 2010で作成していました・・・。
    開けない場合は、Form1に関わるファイルをコピーして持って行ってもらえればいいかと思います。