VB.NET / C# の Windows Forms でフォーム切り替え時に起こる「ちらつき」の解決方法
はじめまして。
理学療法士からシステムエンジニアに転職した25歳のパパ、ましろと申します。
現場では Laravel と VB.NET(WinForms) を中心に開発しています。
今回は、実務で遭遇した フォーム切り替え時の“ちらつき問題” の対処法を共有します。
Double BufferedをTrueにしても、コンポーネントのBackColorのTransparentを諦めても
解決しなかった方は、ぜひ今回のソースを参考にしていただけたらと思います。
では結論から。
'VB.NET
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim newForm As New 画面2
newForm.Opacity = 0
newForm.Show()
Application.DoEvents()
newForm.Opacity = 1
Me.Visible = False
End Sub
//C#
Private void Button1_Click(object sender, EventArgs e)
{
var newForm = new 画面2();
newForm.Opacity = 0;
newForm.Show();
Application.DoEvents();
newForm.Opacity = 1;
this.Visible = False;
}
この記述方法で「ちらつき」を解決することができます。
<以下説明>
スタートアップウィンドウを画面1として、
画面1のコンポーネントであるボタン1をクリックすると画面2に遷移するというシステムを
想定しています。
その画面2に遷移する際の「ちらつき」を解決していきます。
今回紹介するソースは
画面2のデザインにピクチャーボックスやボタンなどが多く配置され、backcolorがtransparent(背景透かし)であるなど、処理が重たくなっている状態にも対応できます。
では、各ステートメントごとに解説していきます。
'VB.NET
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
//C#
Private void Button1_Click(object sender, EventArgs e)
これはボタン1がクリックされた時に実行されるイベントハンドラの定義です。
(※ このように、メソッド名・引数・戻り値の形をまとめて “メソッドシグネチャ”
と呼びます。)
'VB.NET
Dim newForm As New 画面2
//C#
var newForm = new 画面2();
これはローカル変数を用意して新しいフォームである"画面2"を代入しています。
ここでは変数に代入しているだけなので何も起きません。
(※ オブジェクトを作成しているNewをコンストラクタと呼びます)
コンストラクタではない表示方法も後述します。
'VB.NET
newForm.Opacity = 0
//C#
newForm.Opacity = 0;
さて、ここからが本題である「ちらつき」解決のミソになります。
Opacityとは不透明度の意味で初期値が1になります。
今回は イコール0とすることで不透明ではない。つまり、透明の状態にしています。
newFormを透明。つまりボタン1をクリックしたときに表示される”画面2”を
透明にしています。
'VB.NET
newForm.Show()
//C#
newForm.Show();
これはnewFormを表示する。つまり画面2を表示させるメソッドです。
(※ Show()はモードレスで表示、ShowDialog()はモーダルで表示します。)
これをOpacity = 0 のコードの下に記述することで画面2を透明にして表示する
という処理ができます。
'VB.NET
Application.DoEvents()
//C#
Application.DoEvents();
WindowsFormの切り替えでちらつく原因は、ビルドした際にビジュアルスタジオ上の
デザインで配置した各コンポーネントをフォームに配置している最中にも関わらず画面を
表示するからです。いわゆる画面の描画中に表示している状態、、
上記のコードではその処理を指しています。
(※ Double Bufferedがデザイン上で初期値がFalseになっているのでTrueにすると「ちらつき」が解消するという情報はたくさん出てきますが、WindowsFormの描画がGDIというのもありDouble Bufferedはそこまで強力ではないうえ、デザインからはフォームにしか適応できず
ピクチャーボックス等のコンポーネントにはソースにDouble Bufferedのコントロールを
直接組み込まないといけないので、かなり面倒 ... )
'VB.NET
newForm.Opacity = 1
//C#
newForm.Opacity = 1;
Opacityプロパティに1を代入することで不透明にしています。
不透明にすることでユーザーが見えるようになります。
一度ここまでをまとめると
ボタン1をクリックすると、画面2を透明にして表示する→各コンポーネント
を画面2に配置し終わるのを待つ→配置し終わったら画面2の透明を解除する。
このロジックを組み込むことでピクチャーボックス等のtransparentが多くても、
画面切り替えの際に「ちらつく」ことなくスムーズに切り替えられます。
'VB.NET
Me.visible = False
//C#
this.visible = False;
ここはHide()でもClose()でも問題ないのですが、Opacity = 1より下に記述してください。
理由は、画面2の透明を解除する前に画面1を閉じてしまうと
何も表示されない時間が生まれるからです。
(一瞬ではありますが。。それゆえ「ちらつき」ます。)
先述したコンストラクタではない表示法も提示しておきます。
'VB.NET
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
画面2.Opacity = 0
画面2.Show()
Application.DoEvents()
画面2.Opacity = 1
Me.Visible = False
End Sub
//C#
Private void Button1_Click(object sender, EventArgs e)
{
画面2.Opacity = 0;
画面2.Show();
Application.DoEvents();
画面2.Opacity = 1;
this.Visible = False;
}
先程のローカル変数の部分をインスタンスに変えただけです。
以上がVB.NET / C# の Windows Forms でフォーム切り替え時に起こる
「ちらつき」の解決方法 でした。
補足)
今回、クリックイベント時に実行されるように記述していますが
画面2読み込み時に本ロジックを実行すればよいのでは?
という考えもあるかと思います。
ソースとしては
'VB.NET
Private Sub 画面2_load(sender As Object, e As EventArgs) Handles Me.Load
Me.Opacity = 0
Me.show()
End Sub
------------------------------------------------------------------------
Private Sub 画面2_shown(sender As Object, e As EventArgs) Handles Me.shown
Application.DoEvents()
Me.Opacity = 1
End Sub
//C#
Private void 画面2.Load(object sender, EventArgs e)
{
this.Opacity = 0;
this.show();
}
--------------------------------------------------------------
Private void 画面2.Shown(object sender, EventArgs e)
{
Application.DoEvents();
this.Opacity = 1;
}
このようになると思います。
これは間違った記述方法ですが、そのまま進めます。
上記のコードは実行すると「ちらつき」ます。
それはLoadイベントでは暗黙的にshowメソッドも実行されるからです。
つまりshowした後に透明になるという、本題に反する動きをしてしまいます。
暗黙的にshowメソッドが実行されるため、上記Loadイベントハンドラ内の
Me.show()およびthis.show();はゾンビコードになります。
今回の方法はクリックイベント時に実行するのが確実です。
フォーム切り替え時のちらつきでお困りの方はぜひ試してみてください。
ステートメントごとに解説しているので、
フォーム切り替え時の「ちらつき」でお困りの方以外にも参考になると思います。
最後までご覧いただき、ありがとうございました。