- 追加された行はこの色です。
- 削除された行はこの色です。
#title(28)
#title(.NETプログラミング研究 第28号)
#navi(.NETプログラミング研究)
#contents
*28 [#qca88b21]
*.NETプログラミング研究 第28号 [#re2e1ff6]
**.NET Tips [#l4cd1397]
***スプラッシュウィンドウを表示する [#bfd6c36c]
**コメント [#d1503c2c]
#column(注意){{
この記事の最新版は「[[スプラッシュウィンドウを表示する>https://dobon.net/vb/dotnet/form/splashwindow.html]]」で公開しています。
}}
「スプラッシュウィンドウ(Splash Window)」とは、アプリケーション起動時に真っ先に表示され、アプリケーションのロゴやバージョンなどの情報を表示し、自動的に消える(消えないものも稀にあります)ウィンドウです。Microsoft Visual Studio .NETや、Officeなど、多くのアプリケーションでスプラッシュウィンドウが使われています。
まず、スプラッシュウィンドウに必要な機能をあげてみます。
1.メインウィンドウより先に表示される。~
2.画面中央に表示される。~
3.ウィンドウにタイトルバーや枠が無い。~
4.アプリケーションの準備ができたところで、自動的に閉じる。~
1.に関しては、エントリポイント(Mainメソッド)または、メインフォームのコンストラクタやLoadイベントハンドラなどでメインフォームが表示される前にスプラッシュウィンドウを表示するようにすればよいでしょう。2.に関してはスプラッシュウィンドウのフォームのStartPositionプロパティをCenterScreenに、3.に関してはFormBorderStyleプロパティをNoneにすればよいでしょう。
問題は4.です。どのタイミングでスプラッシュウィンドウを閉じるべきでしょうか?メインフォームが表示されるタイミングでということであれば、メインフォームのActivatedイベントで閉じるようにすればよいでしょう。また、「アプリケーションの準備ができた」ということを「アプリケーションがアイドル状態になった時」と解釈すると、Application.Idleイベントで閉じる方法も考えられます。さらに、メインフォームのLoadイベントハンドラの最後で閉じる方法もあります。起動してから指定時間までスプラッシュウィンドウを表示したいときは、タイマーを使う方法もあるかもしれません(個人的な意見としては、スプラッシュウィンドウは用が無くなったらさっさと閉じるべきだと思いますので、この方法はお勧めしたくありません)。
以上の機能以外に、場合によっては、次のような機能も必要になるでしょう。
5.タスクバーに表示しない。(スプラッシュウィンドウがタスクバーに表示されるアプリも多いです。)~
6.メインウィンドウより手前に表示される。~
5.については、フォームのShowInTaskbarプロパティをFalseにすればよいでしょう。6.については、フォームのTopMostプロパティをTrueにする方法があります。しかし、個人的な意見としては、TopMostにはせずに、メインウィンドウの後ろに隠れないようにAddOwnedFormメソッド等を使用するにとどめた方がよいと思います。
以上のことを踏まえ、実際にスプラッシュウィンドウを作ってみます。
まずプロジェクトに新しいフォームを追加し、名前を「SplashForm」とします。SplashFormのStartPositionプロパティをCenterScreen、FormBorderStyleプロパティをNone、さらにShowInTaskbarプロパティをFalseにします。その他、画像の配置など、SplashFormのデザインを適当に行ってください。
さらにSplashFormクラスに次のようなコードを記述します。ここではApplication.IdleイベントでSplashFormを閉じることにします。
#code(vbnet){{
'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
}}
#code(csharp){{
//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を表示させる前にスプラッシュウィンドウを表示させています。
#code(vbnet){{
<STAThread()> _
Shared Sub Main()
'スプラッシュウィンドウを表示
SplashForm.ShowSplash()
'メインウィンドウを表示
Application.Run(New Form1)
End Sub
}}
#code(csharp){{
[STAThread]
static void Main()
{
//スプラッシュウィンドウを表示
SplashForm.ShowSplash();
//メインウィンドウを表示
Application.Run(new Form1());
}
}}
次にスプラッシュウィンドウをメインスレッドとは別のスレッドで表示させるようにしてみます。
まず、スプラッシュウィンドウのフォームクラスは先の例と同様の方法で作成しておき(ここでもクラスの名前を"SplashForm"とします)、SplashFormクラス内に次のようなコードを記述してください。
#code(vbnet){{
'Splashフォーム
Private Shared _form As SplashForm = Nothing
'メインフォーム
Private Shared _mainForm As Form = Nothing
'Splashを表示するスレッド
Private Shared _thread As System.Threading.Thread = Nothing
'/ <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()
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 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
}}
#code(csharp){{
//Splashフォーム
private static SplashForm _form = null;
//メインフォーム
private static Form _mainForm = null;
//Splashを表示するスレッド
private static System.Threading.Thread _thread = null;
/// <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()
{
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を表示させる前にスプラッシュウィンドウを表示させています。
#code(vbnet){{
<STAThread()> _
Shared Sub Main()
Dim mainForm As New Form1
'スプラッシュウィンドウを表示
SplashForm.ShowSplash(mainForm)
'メインウィンドウを表示
Application.Run(mainForm)
End Sub
}}
#code(csharp){{
[STAThread]
static void Main()
{
Form1 mainForm = new Form1();
//スプラッシュウィンドウを表示
SplashForm.ShowSplash(mainForm);
//メインウィンドウを表示
Application.Run(mainForm);
}
}}
(補足:
スプラッシュウィンドウは、アプリケーションが起動してから準備ができるまでに長い時間がかかる時に、ユーザーを不安にさせたり、待たせたりしないために表示するというのが主要な使用目的でしょう。そのため、起動にそれほど時間のかからないアプリではスプラッシュウィンドウは必要ありません。ユーザーの立場からすると、無駄なスプラッシュウィンドウにはうんざりさせられます。)
**.NET質問箱 [#fbecf8a5]
***DataGridセル内の文字列を折り返して表示するには? [#w73d3049]
#column(注意){{
この記事の最新版は「[[DataGridセル内の文字列を折り返して表示する>https://dobon.net/vb/dotnet/datagrid/wrapwordtextcolumn.html]]」で公開しています。
}}
''質問:''
WindowsアプリケーションでDataGridコントロールのセル内の文字列を折り返して表示するにはどのようにすればよいのでしょうか?
''回答:''
DataGridColumnStyleクラスの派生クラスを作成し、そのPaintメソッドをオーバーライドして、文字列を折り返して描画するようにします。
以下にその例を示します。ここでは、DataGridTextBoxColumnクラスを継承し、新しいクラスDataGridTextBoxColumnExを作ります。
#code(vbnet){{
'/ <summary>
'/ DataGridに文字列を折り返して表示するためのDataGridColumnStyle
'/ </summary>
Public Class DataGridTextBoxColumnEx
Inherits DataGridTextBoxColumn
'文字列を描画するマージンを指定する
Private _margin As New Point(0, 2)
'Paintメソッドをオーバーライドする
Protected Overloads Overrides Sub Paint( _
ByVal g As Graphics, _
ByVal bounds As Rectangle, _
ByVal source As CurrencyManager, _
ByVal rowNum As Integer, _
ByVal backBrush As Brush, _
ByVal foreBrush As Brush, _
ByVal alignToRight As Boolean _
)
'表示する文字列を取得
Dim [text] As String = _
GetColumnValueAtRow([source], rowNum).ToString()
Dim sf As New StringFormat
'配置を指定する
Select Case Me.Alignment
Case HorizontalAlignment.Left
sf.Alignment = StringAlignment.Near
Case HorizontalAlignment.Center
sf.Alignment = StringAlignment.Center
Case HorizontalAlignment.Right
sf.Alignment = StringAlignment.Far
End Select
'テキストの方向を指定する
If alignToRight Then
sf.FormatFlags = sf.FormatFlags Or _
StringFormatFlags.DirectionRightToLeft
End If
'背景を塗りつぶす
g.FillRectangle(backBrush, bounds)
'文字列を描画する範囲を取得する
Dim rectf As New RectangleF(bounds.X + _margin.X, _
bounds.Y + _margin.Y, _
bounds.Width - _margin.X * 2, _
bounds.Height - _margin.Y * 2)
'文字列を描画する
g.DrawString([text], Me.DataGridTableStyle.DataGrid.Font, _
foreBrush, rectf, sf)
sf.Dispose()
End Sub
End Class
}}
#code(csharp){{
/// <summary>
/// DataGridに文字列を折り返して表示するためのDataGridColumnStyle
/// </summary>
public class DataGridTextBoxColumnEx : DataGridTextBoxColumn
{
//文字列を描画するマージンを指定する
Point _margin = new Point(0, 2);
//Paintメソッドをオーバーライドする
protected override void Paint(Graphics g,
Rectangle bounds,
CurrencyManager source,
int rowNum,
Brush backBrush,
Brush foreBrush,
bool alignToRight)
{
//表示する文字列を取得
string text =
GetColumnValueAtRow(source, rowNum).ToString();
StringFormat sf = new StringFormat();
//配置を指定する
switch (this.Alignment)
{
case HorizontalAlignment.Left:
sf.Alignment = StringAlignment.Near;
break;
case HorizontalAlignment.Center:
sf.Alignment = StringAlignment.Center;
break;
case HorizontalAlignment.Right:
sf.Alignment = StringAlignment.Far;
break;
}
//テキストの方向を指定する
if (alignToRight)
sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
//背景を塗りつぶす
g.FillRectangle(backBrush, bounds);
//文字列を描画する
g.DrawString(text, this.DataGridTableStyle.DataGrid.Font,
foreBrush, bounds.Inflate(-_margin.X, -_margin.Y), sf);
sf.Dispose();
}
}
}}
(上の例ではマージンを"_margin"で指定していますが、これがないと文字列が描画される位置が上過ぎて、セルが編集になった時もTextBoxの上にちょっとはみ出てしまいます。)
DataGridTextBoxColumnExクラスを使用するには、文字列を折り返して表示したい列の列スタイルにDataGridTextBoxColumnExオブジェクトを設定します。詳しい方法は、次のページをご覧ください。
-[[DataGridの列の幅を変更する>https://dobon.net/vb/dotnet/datagrid/columnwidth.html]]
この記事の基になった掲示板のスレッド
-[[DataGridのセル内の文字列を折り返し表示する方法: 投稿者(敬称略):吉田、管理人>https://dobon.net/vb/bbs/log3-1/208.html]]
***フォームのコレクションを作成するには? [#gc368011]
#column(注意){{
この記事の最新版は「[[VB6のFormsコレクションに代わるものは?>https://dobon.net/vb/dotnet/vb6/formscollection.html]]」で公開しています。
}}
''質問:''
Visual Basic 6.0 にはFormsコレクションがありましたが、.NETにフォームのコレクションはありますか?
''回答:''
VB6のFormsコレクションに相当するものは.NET Frameworkでは用意されていませんし、フォームオブジェクト専用のコレクションもありません。
「マイクロソフト サポート技術情報 - 308537」の「[HOW TO] Visual Basic .NET で Forms コレクションを作成する方法」では、カスタムのFormsコレクションを作成する方法が紹介されています。
-[[[HOW TO] Visual Basic .NET で Forms コレクションを作成する方法>http://support.microsoft.com/default.aspx?scid=kb;ja;JP308537]]
しかしここで紹介されているクラスでは、インデックスを指定してオブジェクトを取得できず、不便です。
そこで、インデックスを指定してオブジェクトを取得できるようにし、さらにInsert、IndexOf、Containsメソッドを追加したコレクションクラスを以下に紹介します。
#code(vbnet){{
'/ <summary>
'/ フォームのコレクション
'/ </summary>
Public Class FormCollection
Inherits CollectionBase
'/ <summary>
'/ インデクサ
'/ </summary>
Default Public Property Item(ByVal index As Integer) As Form
Get
Return CType(List(index), Form)
End Get
Set(ByVal Value As Form)
List(index) = value
End Set
End Property
'/ <summary>
'/ コレクションにフォームを追加する
'/ </summary>
'/ <param name="frm">追加するフォーム</param>
'/ <returns>追加された位置</returns>
Public Function Add(ByVal frm As Form) As Integer
Return List.Add(frm)
End Function
'/ <summary>
'/ コレクションからフォームを削除する
'/ </summary>
'/ <param name="frm">削除するフォーム</param>
Public Sub Remove(ByVal frm As Form)
List.Remove(frm)
End Sub
'/ <summary>
'/ コレクションにフォームを挿入する
'/ </summary>
'/ <param name="index">挿入する位置</param>
'/ <param name="frm">挿入するフォーム</param>
Public Sub Insert(ByVal index As Integer, ByVal frm As Form)
List.Insert(index, frm)
End Sub
'/ <summary>
'/ フォームのインデックスを調べる
'/ </summary>
'/ <param name="frm">検索するフォーム</param>
'/ <returns>フォームのインデックス</returns>
Public Function IndexOf(ByVal frm As Form) As Integer
Return List.IndexOf(frm)
End Function
'/ <summary>
'/ コレクションにフォームが格納されているか調べる
'/ </summary>
'/ <param name="frm">検索するフォーム</param>
'/ <returns>コレクションに格納されている時はtrue</returns>
Public Function Contains(ByVal frm As Form) As Boolean
Return List.Contains(frm)
End Function
End Class
}}
#code(csharp){{
/// <summary>
/// フォームのコレクション
/// </summary>
public class FormCollection : CollectionBase
{
/// <summary>
/// インデクサ
/// </summary>
public Form this[int index]
{
get
{
return (Form) List[index];
}
set
{
List[index] = value;
}
}
/// <summary>
/// コレクションにフォームを追加する
/// </summary>
/// <param name="frm">追加するフォーム</param>
/// <returns>追加された位置</returns>
public int Add(Form frm)
{
return List.Add(frm);
}
/// <summary>
/// コレクションからフォームを削除する
/// </summary>
/// <param name="frm">削除するフォーム</param>
public void Remove(Form frm)
{
List.Remove(frm);
}
/// <summary>
/// コレクションにフォームを挿入する
/// </summary>
/// <param name="index">挿入する位置</param>
/// <param name="frm">挿入するフォーム</param>
public void Insert(int index, Form frm)
{
List.Insert(index, frm);
}
/// <summary>
/// フォームのインデックスを調べる
/// </summary>
/// <param name="frm">検索するフォーム</param>
/// <returns>フォームのインデックス</returns>
public int IndexOf(Form frm)
{
return List.IndexOf(frm);
}
/// <summary>
/// コレクションにフォームが格納されているか調べる
/// </summary>
/// <param name="frm">検索するフォーム</param>
/// <returns>コレクションに格納されている時はtrue</returns>
public bool Contains(Form frm)
{
return List.Contains(frm);
}
}
}}
このコレクションの使い方は、例えば次のような感じです。
#code(vbnet){{
'Dim _forms As New FormCollection
'というフィールドが宣言されているものとする
'Form1オブジェクトを作成
Dim f As New Form1
'コレクションに追加する
_forms.Add(f)
'インデックス0のフォームを表示する
_forms(0).ShowDialog()
}}
#code(csharp){{
//FormCollection _forms = new FormCollection();
//というフィールドが宣言されているものとする
//Form1オブジェクトを作成
Form1 f = new Form1();
//コレクションに追加する
_forms.Add(f);
//インデックス0のフォームを表示する
_forms[0].ShowDialog()
}}
なお、このフォームコレクションには、開かれたフォームが自動的に追加されたり、閉じられたフォームが自動的に削除される機能がありません。これらの処理は自分で行う必要があります。
この記事の基になった掲示板のスレッド
-[[Formsコレクションについて: 投稿者(敬称略):はるか、よねKEN、tina、管理人>https://dobon.net/vb/bbs/log3-1/208.html]]
**コメント [#mfda5dc1]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]] [[:Category/ASP.NET]],2010-03-21 (日) 01:48:14,DOBON!,2010-03-21 (日) 01:48:14,DOBON!)
#pageinfo([[:Category/.NET]],2004-03-08 (月) 06:00:00,DOBON!,2010-03-21 (日) 01:49:21,DOBON!)