┏第13号━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ .NETプログラミング研究 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜メニュー
■.NET Tips
・フォームの形を変える
■.NET質問箱
・メールのサブジェクトをデコードするには?
・フォームが閉じられる時その原因を知るには?
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
───────────────────────────────
■.NET Tips
───────────────────────────────
●フォームの形を変える
フォームの形を四角(矩形)以外の形に変える方法としてここでは、
Control.Regionプロパティを使う方法と、Form.TransparencyKeyプロ
パティを使う方法の2つを紹介します。まずはControl.Regionプロパテ
ィを使った方法から。
形を変えたいフォームのRegionプロパティに、その形状を示した
Regionオブジェクトを指定することにより、フォームの形を変えるこ
とが出来ます。
次の例はフォームをドーナッツ型にするコードです。ここではフォー
ムのLoadイベントハンドラ内にコードを書いていますが、コンストラ
クタ内の適当な位置などに記述してもかまいません。
'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'フォームの大きさを適当に変更
Me.SetBounds(Me.Left, Me.Top, 301, 301, BoundsSpecified.Size)
'GraphicsPathオブジェクトの作成
Dim myGraphicsPath As System.Drawing.Drawing2D.GraphicsPath = _
New System.Drawing.Drawing2D.GraphicsPath()
'丸を描く
myGraphicsPath.AddEllipse(New Rectangle(0, 0, 300, 300))
'真ん中を丸くくりぬく
myGraphicsPath.AddEllipse(New Rectangle(100, 100, 100, 100))
'Regionプロパティの設定
Me.Region = New Region(myGraphicsPath)
End Sub
'・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
//[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・
private void Form1_Load(object sender, System.EventArgs e)
{
//フォームの大きさを適当に変更
this.SetBounds(this.Left, this.Top, 301, 301, BoundsSpecified.Size);
//GraphicsPathオブジェクトの作成
System.Drawing.Drawing2D.GraphicsPath myGraphicsPath =
new System.Drawing.Drawing2D.GraphicsPath();
//丸を描く
myGraphicsPath.AddEllipse(new Rectangle(0, 0, 300, 300));
//真ん中を丸くくりぬく
myGraphicsPath.AddEllipse(new Rectangle(100, 100, 100, 100));
//Regionプロパティの設定
this.Region = new Region(myGraphicsPath);
}
//・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
次の例はフォームの形を文字(この例では"DOBON!")にするものです。
'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim myGraphicsPath As New System.Drawing.Drawing2D.GraphicsPath()
'文字のサイズは50
myGraphicsPath.AddString("DOBON!", New FontFamily("Arial"), _
FontStyle.Bold, 50, New Point(0, 0), StringFormat.GenericDefault)
Me.Region = New Region(myGraphicsPath)
End Sub
'・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
//[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・
private void Form1_Load(object sender, System.EventArgs e)
{
System.Drawing.Drawing2D.GraphicsPath myGraphicsPath =
new System.Drawing.Drawing2D.GraphicsPath();
//文字のサイズは50
myGraphicsPath.AddString("DOBON!", new FontFamily("Arial"),
(int) FontStyle.Bold, 50, new Point(0, 0),
StringFormat.GenericDefault);
this.Region = new Region(myGraphicsPath);
}
//・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
そのほかの形に変える例につきましては、下のURLをご覧ください。
・フォームやコントロールの形を変える
http://dobon.net/vb/dotnet/form/formregion.html
次にForm.TransparencyKeyプロパティを使ってフォームの形を変える
方法を紹介します。
Windows2000以降のOSであれば、Form.TransparencyKeyプロパティによ
り、フォームで透明にしたい色を指定できます。この
TransparencyKeyを使うことにより、自由な形のフォームを簡単に作れ
そうです。つまり、フォームの形としたい形が描かれた画像ファイル
を用意し、フォームにその画像を描画し、画像の背景色をフォームの
TransparencyKeyに指定する訳です。
しかし残念なことに実際にはそう簡単にはいきません。私の試したと
ころでは、Windowsの設定で「画面のプロパティ」の「画面の色」が「
High Color(16ビット)」以下になっている時はうまく行きますが、
「True Color(32ビット)」の時はTransparencyKeyに指定した色でも
透明になりませんでした。(環境により違いがあるかもしれません。)
いろいろ試してみたところ、少なくとも私の環境では次のような方法
により、True Colorの時でも成功するようになりました。まずフォー
ムの背景色を透明にしたい色にし、フォームのTransparencyKeyにもそ
の色を指定します。フォームの形に使う画像ファイルはBitmapオブジ
ェクトとして読み込み、MakeTransparentメソッドにより、透明にした
い色(背景色)を透明色にします。(透明色を指定して保存したGif画
像を使うという手もあります。)
画像をフォームに描画するには、BackgroundImageプロパティを使わず
に、フォームのPaintイベントハンドラで描画するようにします。(こ
の方法がすべての環境でうまく行くか分かりませんので、情報をいた
だければ助かります。)
次の例ではフォームの形を"form.bmp"という画像ファイルに保存し、
これを使ってフォームForm1の形を作っています。ここでは白を透明色
としています。
'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
Dim _formBitmap As Bitmap
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'TransparencyKeyプロパティを指定する前に画像を読み込む
'フォームの形の画像を読み込む
_formBitmap = New Bitmap("form.bmp")
'画像の透明色を指定する
_formBitmap.MakeTransparent(Color.White)
'フォームの境界線をなくす
Me.FormBorderStyle = FormBorderStyle.None
'大きさを適当に変更
Me.Size = New Size(100, 100)
'透明を指定する
Me.TransparencyKey = Color.White
'フォームの背景色を透明色にする
Me.BackColor = Color.White
End Sub
Private Sub Form1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles MyBase.Paint
'フォームの形の画像を描画する
e.Graphics.DrawImage(_formBitmap, 0, 0)
End Sub
'・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
//[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・
Bitmap _formBitmap;
private void Form1_Load(object sender, System.EventArgs e)
{
//TransparencyKeyプロパティを指定する前に画像を読み込む
//フォームの形の画像を読み込む
_formBitmap = new Bitmap(@"form.bmp");
//画像の透明色を指定する
_formBitmap.MakeTransparent(Color.White);
//フォームの境界線をなくす
this.FormBorderStyle = FormBorderStyle.None;
//大きさを適当に変更
this.Size = new Size(100, 100);
//透明を指定する
this.TransparencyKey = Color.White;
//フォームの背景色を透明色にする
this.BackColor = Color.White;
}
private void Form1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
//フォームの形の画像を描画する
e.Graphics.DrawImage(_formBitmap, 0, 0);
}
//・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
・フォームウィンドウの特定の色を透明にする
http://dobon.net/vb/dotnet/form/transparencykey.html
───────────────────────────────
■.NET質問箱
───────────────────────────────
●メールのサブジェクトをデコードするには?
質問:
受信したメールのSubjectをデコードしたいのですが、どのようにすれ
ばよいのでしょうか?
例「=?ISO-2022-JP?B?GyRCJCIkMSReJDckRiQqJGEkRyRIJCYhKhsoSg==?=」
答え:
ちゃんとしたものを作るにはRFC2047の知識が必要になると思いますが、
「とりあえず」的なもの(Base64形式のみ対応)であれば、次のよう
な簡単なコード(メソッド)で実現できます。
・RFC2047
http://www.ietf.org/rfc/rfc2047.txt
'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
'/
'/ メールのサブジェクトをデコードする
'/
'/ デコードするメールサブジェクト
'/ デコードされた文字列
Private Shared Function DecodeMailSubject(ByVal subject As String) As String
'要素を分解する
Dim s As String() = subject.Split("?"c)
Dim b() As Byte
If s(2) = "B" Then
'Base64形式の時
b = System.Convert.FromBase64String(s(3))
Else
'Base64形式のみ対応
Throw New Exception("未対応のエンコード形式です。")
End If
's(1)をEncoding名として、デコードする
Return System.Text.Encoding.GetEncoding(s(1)).GetString(b)
End Function
'・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
//[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・
///
/// メールのサブジェクトをデコードする
///
/// デコードするメールサブジェクト
/// デコードされた文字列
private static string DecodeMailSubject(string subject)
{
//要素を分解する
string[] s = subject.Split('?');
byte[] b;
if (s[2] == "B")
{
//Base64形式の時
b = System.Convert.FromBase64String(s[3]);
}
else
{
//Base64形式のみ対応
throw new Exception("未対応のエンコード形式です。");
}
//s[1]をEncoding名として、デコードする
return System.Text.Encoding.GetEncoding(s[1]).GetString(b);
}
//・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
・メールのサブジェクトのデコード
http://www.sky-j.com/viewlist.php?arg_forum_id=38&arg_thread_id=675&arg_message_id=675
───────────────────────────────
●フォームが閉じられる時その原因を知るには?
質問:
VB6のQueryUnloadイベントにおけるUnloadModeのように、フォームが
閉じられる時にどうしてフォームが閉じられようとしているのか(ウ
ィンドウのCloseボタンのクリックにより閉じられようとしているのか、
コードのCloseメソッドにより閉じられようとしているのか等)知るに
はどのようにすればよいのでしょうか?
答え:
これにはいくつかの方法があるようです。
一つ目は、フォームのWndProcメソッドをオーバーライドし、送られて
くるメッセージを調べるという方法です。次の例では、
WM_ENDSESSION、WM_SYSCOMMAND、WM_CLOSEが送られてきたか調べ、フ
ォームが閉じられる原因がOSのシャットダウンによるか、Xボタンやコ
ントロールメニューによるか、コードによるか判断しています。
'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Const WM_CLOSE As Integer = &H10
Const WM_ENDSESSION As Integer = &H16
Const WM_SYSCOMMAND As Integer = &H112
Const SC_CLOSE As Integer = &HF060
Select Case m.Msg
Case WM_ENDSESSION
'OSのシャットダウンなどで閉じられようとしている
Console.WriteLine("WM_ENDSESSION")
Case WM_SYSCOMMAND
If m.WParam.ToInt32() = SC_CLOSE Then
'Xボタン、コントロールメニューの「閉じる」、
'コントロールボックスのダブルクリック、
'Atl+F4などにより閉じられようとしている
Console.WriteLine("SC_CLOSE")
End If
Case WM_CLOSE
'Application.Exit以外などで閉じられようとしている
Console.WriteLine("WM_CLOSE")
End Select
MyBase.WndProc(m)
End Sub
'・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
//[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・
protected override void WndProc(ref Message m)
{
const int WM_CLOSE = 0x0010;
const int WM_ENDSESSION = 0x16;
const int WM_SYSCOMMAND = 0x112;
const int SC_CLOSE = 0xF060;
switch (m.Msg)
{
case WM_ENDSESSION:
//OSのシャットダウンなどで閉じられようとしている
Console.WriteLine("WM_ENDSESSION");
break;
case WM_SYSCOMMAND:
if (m.WParam.ToInt32() == SC_CLOSE)
//Xボタン、コントロールメニューの「閉じる」、
//コントロールボックスのダブルクリック、
//Atl+F4などにより閉じられようとしている
Console.WriteLine("SC_CLOSE");
break;
case WM_CLOSE:
//Application.Exit以外などで閉じられようとしている
Console.WriteLine("WM_CLOSE");
break;
}
base.WndProc (ref m);
}
//・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
二番目の方法は、StackFrameを使うというちょっと変わった方法で、
これは GotDotNet Message Boards で紹介されています。
・GotDotNet Message Boards - Form.Closing...
http://www.gotdotnet.com/Community/MessageBoard/Thread.aspx?id=40651
ここで紹介されているYeahIGotDotNetさん、MikeWill34さんの書いた
コード及び、CodeProjectで紹介されているEvilDoctorSmithさんのコー
ドを参考にさせていただき、次のようなコードを書いてみました。詳
しくは上記URLをご覧ください。
・The Code Project - Find out what's closing your application
http://www.codeproject.com/useritems/FormClosing.asp
'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
Private Sub Form1_Closing(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) _
Handles MyBase.Closing
Dim stack As New System.Diagnostics.StackTrace(True)
Dim frame7 As System.Diagnostics.StackFrame = stack.GetFrame(7)
Select Case frame7.GetMethod().Name
Case "DispatchMessageW"
Console.WriteLine("タスクマネージャーによる")
Case "SendMessage"
Console.WriteLine("コードによる")
Case "CallWindowProc"
If stack.FrameCount > 14 Then
Dim frame14 As System.Diagnostics.StackFrame = _
stack.GetFrame(14)
If frame14.GetMethod().Name = "WmSysCommand" Then
Console.WriteLine( _
"Xボタンまたはコントロールメニューによる")
Else
If frame14.GetMethod().Name = "WndProc" Then
Console.WriteLine("OSのシャットダウンによる")
End If
End If
End If
Case "DefMDIChildProc"
Console.WriteLine( _
"MDI子フォームのXボタンまたはコントロールメニューによる")
Case "DefFrameProc"
Console.WriteLine("MDI親フォームが閉じられたことによる")
Case "ShowDialog"
Console.WriteLine("モーダルダイアログが閉じられたことによる")
Case Else
Console.WriteLine("原因不明")
End Select
End Sub
'・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
//[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・
private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
System.Diagnostics.StackTrace stack =
new System.Diagnostics.StackTrace(true);
System.Diagnostics.StackFrame frame7 = stack.GetFrame(7);
switch (frame7.GetMethod().Name)
{
case "DispatchMessageW":
Console.WriteLine("タスクマネージャーによる");
break;
case "SendMessage":
Console.WriteLine("コードによる");
break;
case "CallWindowProc":
if (stack.FrameCount > 14)
{
System.Diagnostics.StackFrame frame14 =
stack.GetFrame(14);
if (frame14.GetMethod().Name == "WmSysCommand")
Console.WriteLine(
"Xボタンまたはコントロールメニューによる");
else if (frame14.GetMethod().Name == "WndProc")
Console.WriteLine("OSのシャットダウンによる");
}
break;
case "DefMDIChildProc":
Console.WriteLine(
"MDI子フォームのXボタンまたはコントロールメニューによる");
break;
case "DefFrameProc":
Console.WriteLine("MDI親フォームが閉じられたことによる");
break;
case "ShowDialog":
Console.WriteLine("モーダルダイアログが閉じられたことによる");
break;
default:
Console.WriteLine("原因不明");
break;
}
}
//・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
最後に紹介するのは、hidden windowを使った方法です(一番目の方法
を拡張したような感じです)。この方法につきましては、下記URLで紹
介されていますので、興味のある方はご覧ください。
・Visual Studio Magazine - Determine a Form's UnloadMode
http://www.fawcette.com/Archives/premier/mgznarch/vbpj/2001/11nov01/qa0111/qa0111.asp
・フォームのXボタンの制御
http://www.sky-j.com/viewlist.php?arg_forum_id=38&arg_thread_id=772&arg_message_id=772
===============================
■このマガジンの購読、購読中止、バックナンバー、説明に関しては
次のページをご覧ください。
http://www.mag2.com/m/0000104516.htm
■発行人・編集人:どぼん!
http://dobon.net
dobon@bigfoot.com
■ご質問等はメールではなく、掲示板へお願いいたします。
http://dobon.net/bbs
■上記メールアドレスへのメールは確実に読まれる保障はありません
(スパム、ウィルス対策です)。メールは下記URLのフォームメール
から送信してください。
http://dobon.net/mail.html
Copyright (c) 2003 DOBON! All rights reserved.
===============================