┏第35号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ──<メニュー>─────────────────────── ■.NET質問箱 ・ComboBoxで上下矢印キーで項目を変更できないようにするには? ・PageSetupDialogのMarginsが正常に機能しない ・TreeViewのNodeの右に色の違う文字列を描画するには? ■コンピュータ雑学 ・「C言語」の「C」の意味は? ─────────────────────────────── ─────────────────────────────── ■.NET質問箱 ─────────────────────────────── 「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込 まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、 Q&A形式にまとめて紹介します。 [URL]どぼん!のプログラミング掲示板 http://dobon.net/vb/bbs.html ●ComboBoxで上下矢印キーで項目を変更できないようにするには? 【質問】 WindowsアプリケーションのComboBoxコントロールで、マウスだけで項 目を選択でき、上下矢印キーによる選択ができないようにしたいので すが、どのような方法がありますか? 【回答】 簡単な方法としては、ComboBoxのKeyDownイベントハンドラで上下矢印 キーが押された時にKeyEventArgsオブジェクトのHandledプロパティを Trueにして、キー入力を無効にする方法があります。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 'ComboBox1のKeyDownイベントハンドラ Private Sub ComboBox1_KeyDown(ByVal sender As Object, _ ByVal e As System.Windows.Forms.KeyEventArgs) _ Handles ComboBox1.KeyDown If e.KeyCode = Keys.Down Or e.KeyCode = Keys.Up Then e.Handled = True End If End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //ComboBox1のKeyDownイベントハンドラ private void ComboBox1_KeyDown( object sender, System.Windows.Forms.KeyEventArgs e) { if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up) e.Handled = true; } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ しかし残念ながらこの方法は、.NET Framework 1.0では正常に働きま せん。(1.1ではこのバグが修正されています。).NET Framework 1. 0では、ComboBoxの派生クラスを作成し、WndProcや PreProcessMessageメソッドをオーバーライドすることにより、上下矢 印キーを無視するなどの方法を使用する必要があります。 次にPreProcessMessageメソッドをオーバーライドすることにより上下 矢印キーでの操作を無効にしたComboBoxの派生クラス(MyComboBoxク ラス)のサンプルを示します。このクラスを実際に使用するには、 "System.Windows.Forms.ComboBox"の代わりに"MyComboBox"を使うよう にします。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ''' ''' 上下矢印キーで項目を変更できないComboBox ''' Public Class MyComboBox Inherits System.Windows.Forms.ComboBox Private WM_KEYDOWN As Integer = &H100 Public Overrides Function PreProcessMessage( _ ByRef msg As Message) As Boolean If msg.Msg = WM_KEYDOWN Then '上下矢印キー操作を無効にする Dim keyCode As Keys = _ CType(msg.WParam.ToInt32(), Keys) And Keys.KeyCode If keyCode = Keys.Up Or keyCode = Keys.Down Then Return True End If End If Return MyBase.PreProcessMessage(msg) End Function End Class ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ /// /// 上下矢印キーで項目を変更できないComboBox /// public class MyComboBox : System.Windows.Forms.ComboBox { private const int WM_KEYDOWN = 0x100; public override bool PreProcessMessage(ref Message msg) { if (msg.Msg == WM_KEYDOWN) { //上下矢印キー操作を無効にする Keys keyCode = (Keys)(int)msg.WParam & Keys.KeyCode; if (keyCode == Keys.Up || keyCode == Keys.Down) return true; } return base.PreProcessMessage(ref msg); } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ○この記事の基になった掲示板のスレッド [題名] ComboBoxのItemの選択について [投稿者(敬称略)] tab, 管理人, ピラルク [URL] http://dobon.net/vb/bbs/log3-2/695.html ─────────────────────────────── ●PageSetupDialogのMarginsが正常に機能しない 【質問】 PageSetupDialogを使ってページ設定ダイアログを表示したとき、マー ジン指定が正常に機能しません。例えば次のようなコードでマージン の上下左右に1インチを指定してもページ設定ダイアログでは10センチ と表示され、さらに「OK」で確定後、PageSetupDialogオブジェクトの PageSettings.Marginsの値が上下左右39になってしまいます。なぜで しょうか? ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Dim PageSetupDialog1 As New PageSetupDialog PageSetupDialog1.Document = New System.Drawing.Printing.PrintDocument 'マージンを指定する PageSetupDialog1.PageSettings.Margins = _ New System.Drawing.Printing.Margins(100, 100, 100, 100) 'ページ設定ダイアログを表示する If PageSetupDialog1.ShowDialog() = DialogResult.OK Then Console.WriteLine(PageSetupDialog1.PageSettings.Margins) End If ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ PageSetupDialog PageSetupDialog1 = new PageSetupDialog(); PageSetupDialog1.Document = new System.Drawing.Printing.PrintDocument(); //マージンを指定する PageSetupDialog1.PageSettings.Margins = new System.Drawing.Printing.Margins(100, 100, 100, 100); //ページ設定ダイアログを表示する if (PageSetupDialog1.ShowDialog() == DialogResult.OK) //指定されたマージンを表示する Console.WriteLine(PageSetupDialog1.PageSettings.Margins); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 【回答】 これは.NET Frameworkのバグです。マイクロソフトサポート技術情報 814355で紹介されています。 [URL]マイクロソフト サポート技術情報 - 814355 BUG: PageSetupDialog が表示される度、余白の値が減少します。 http://support.microsoft.com/?id=814355 マイクロソフトサポート技術情報では回避法はコントロールパネルの 「地域と言語のオプション」の設定を変更するということですが、そ れができれば苦労はありません。 今後もこのバグが修正されないという前提のもとでは、回避法として、 システムでメートル法が選択されているか確認し、そうであればペー ジ設定ダイアログを表示する前にマージンの単位を変更するという方 法が考えられます。この方法はニュースグループで紹介されています。 [URL]ニュースグループ microsoft.public.dotnet.framework.drawing PageSetupDialog and page margins http://groups.google.co.jp/groups?hl=ja&lr=&ie=UTF-8&inlang=ja&threadm=u1BU9.113980%24TC5.3653214%40twister1.libero.it この方法を使って問題を回避したコードの例を示します。ただし、将 来このバグが修正された時には逆にバグとなってしまうことに注意し てください。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Dim PageSetupDialog1 As New PageSetupDialog PageSetupDialog1.Document = New System.Drawing.Printing.PrintDocument 'マージンを指定する PageSetupDialog1.PageSettings.Margins = _ New System.Drawing.Printing.Margins(100, 100, 100, 100) 'メートル法を使っている時は、メートルに直す If System.Globalization.RegionInfo.CurrentRegion.IsMetric Then PageSetupDialog1.PageSettings.Margins.Top *= 2.54 PageSetupDialog1.PageSettings.Margins.Bottom *= 2.54 PageSetupDialog1.PageSettings.Margins.Left *= 2.54 PageSetupDialog1.PageSettings.Margins.Right *= 2.54 End If 'ページ設定ダイアログを表示する If PageSetupDialog1.ShowDialog() = DialogResult.OK Then Console.WriteLine(PageSetupDialog1.PageSettings.Margins) ElseIf System.Globalization.RegionInfo.CurrentRegion.IsMetric Then 'また元に戻す PageSetupDialog1.PageSettings.Margins.Top /= 2.54 PageSetupDialog1.PageSettings.Margins.Bottom /= 2.54 PageSetupDialog1.PageSettings.Margins.Left /= 2.54 PageSetupDialog1.PageSettings.Margins.Right /= 2.54 End If ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ PageSetupDialog PageSetupDialog1 = new PageSetupDialog(); PageSetupDialog1.Document = new System.Drawing.Printing.PrintDocument(); //マージンを指定する PageSetupDialog1.PageSettings.Margins = new System.Drawing.Printing.Margins(100, 100, 100, 100); //メートル法を使っている時は、メートルに直す if (System.Globalization.RegionInfo.CurrentRegion.IsMetric) { PageSetupDialog1.PageSettings.Margins.Top = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Top * 2.54); PageSetupDialog1.PageSettings.Margins.Bottom = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Bottom * 2.54); PageSetupDialog1.PageSettings.Margins.Left = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Left * 2.54); PageSetupDialog1.PageSettings.Margins.Right = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Right * 2.54); } //ページ設定ダイアログを表示する if (PageSetupDialog1.ShowDialog() == DialogResult.OK) //指定されたマージンを表示する Console.WriteLine(PageSetupDialog1.PageSettings.Margins); else if (System.Globalization.RegionInfo.CurrentRegion.IsMetric) { //また元に戻す PageSetupDialog1.PageSettings.Margins.Top = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Top / 2.54); PageSetupDialog1.PageSettings.Margins.Bottom = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Bottom / 2.54); PageSetupDialog1.PageSettings.Margins.Left = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Left / 2.54); PageSetupDialog1.PageSettings.Margins.Right = (int)Math.Round( PageSetupDialog1.PageSettings.Margins.Right / 2.54); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ [題名] PageSetupDialogのマージン [投稿者(敬称略)] DEG, 管理人 [URL] http://dobon.net/vb/bbs/log3-2/671.html ─────────────────────────────── ●TreeViewのNodeの右に色の違う文字列を描画するには? 【質問】 Outlook ExpressのTreeViewでは、未読のメール数がノードの右側に青 色で表示されますが、同じようなことを.NETでできませんか? 【回答】 これを実現させる方法がC# Helpで紹介されています。 [URL]C# Help - Outlook Style Tree View http://www.csharphelp.com/archives2/archive286.html この記事ではC#のコードしか紹介されていませんが、これをVB.NETの コードにしたものを掲示板でよねKENさんから投稿していただきま した。 これらのコードを以下に紹介させていただきます(一部変更していま すが、ほぼ同じです)。フォームにツリービューコントロール TreeView1が配置されているものとし、TreeView1のあるノードの末尾 にそのノードの子ノードの数(孫ノード以降は含めない)を青色で表 示しています。TreeView1のあるフォームクラスに記述してください。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 'Imports System.Runtime.InteropServices 'が宣言されているものとする Public Structure NMHDR Public hwndFrom As IntPtr Public idFrom As Integer Public code As UInt32 End Structure Public Structure NMCUSTOMDRAW Public hdr As NMHDR Public dwDrawStage As Integer Public hdc As Integer Public x1 As Integer Public y1 As Integer Public x2 As Integer Public y2 As Integer Public dwItemSpec As Integer Public uItemState As Integer Public lItemlParam As Integer End Structure Private Const WM_NOTIFY As Integer = &H4E Private ReadOnly NM_CUSTOMDRAW As UInt32 = _ Convert.ToUInt32(4294967284) Private Const CDDS_ITEMPREPAINT As Integer = 65537 Private Const CDRF_NOTIFYSUBITEMDRAW As Integer = 32 Protected Overrides Sub WndProc(ByRef m As Message) Dim lp2 As NMCUSTOMDRAW Dim lp As NMHDR If (m.Msg = WM_NOTIFY) Then lp = Marshal.PtrToStructure(m.LParam, lp.GetType()) If (lp.code.CompareTo(NM_CUSTOMDRAW) = 0) Then lp2 = Marshal.PtrToStructure(m.LParam, lp2.GetType()) If (lp2.dwDrawStage = CDDS_ITEMPREPAINT) Then MyBase.WndProc(m) TreeViewPaint(m) m.Result = IntPtr.Zero Return Else m.Result = New IntPtr(CDRF_NOTIFYSUBITEMDRAW) End If End If End If MyBase.WndProc(m) End Sub Public Sub TreeViewPaint(ByRef m As Message) Dim lp2 As NMCUSTOMDRAW Dim g As Graphics Dim node As TreeNode Dim strText As String Dim x1, y1 As Long lp2 = Marshal.PtrToStructure(m.LParam, lp2.GetType()) g = System.Drawing.Graphics.FromHwnd(Me.TreeView1.Handle) node = TreeView1.GetNodeAt(lp2.x1 + 1, lp2.y1 + 1) x1 = lp2.x1 + node.Bounds.X + node.Bounds.Width + 5 y1 = lp2.y1 strText = "( " + node.Nodes.Count.ToString() + " )" 'Nodeの子ノード数をNodeの後ろに青で表示する g.DrawString(strText, TreeView1.Font, _ System.Drawing.Brushes.Blue, x1, y1, _ System.Drawing.StringFormat.GenericTypographic) End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ private unsafe struct NMHDR { public uint hwndFrom; public uint idFrom; public uint code; } private unsafe struct NMCUSTOMDRAW { public NMHDR hdr; public uint dwDrawStage; public uint hdc; public uint x1; public uint y1; public uint x2; public uint y2; public uint dwItemSpec; public uint uItemState; public uint lItemlParam; } private const uint WM_NOTIFY = 0x4E; private const uint NM_CUSTOMDRAW = 4294967284; private const uint CDDS_ITEMPREPAINT = 65537; private const uint CDRF_NOTIFYSUBITEMDRAW = 32; protected unsafe override void WndProc(ref Message m) { NMCUSTOMDRAW *lp2; NMHDR *lp; if (m.Msg == WM_NOTIFY) { lp = (NMHDR*) m.LParam.ToPointer(); if (lp->code == NM_CUSTOMDRAW) { lp2 = (NMCUSTOMDRAW*)m.LParam.ToPointer(); if (lp2->dwDrawStage == CDDS_ITEMPREPAINT) { base.WndProc(ref m); TreeViewPaint(ref m); m.Result =(IntPtr)0; return; } else { m.Result =(IntPtr)CDRF_NOTIFYSUBITEMDRAW; } } } base.WndProc(ref m); } private unsafe void TreeViewPaint(ref Message m) { NMCUSTOMDRAW *lp2; System.Drawing.Graphics g; System.Windows.Forms.TreeNode node; string strText; long x1, y1; lp2 = (NMCUSTOMDRAW*)m.LParam.ToPointer(); g = System.Drawing.Graphics.FromHwnd(TreeView1.Handle); node = TreeView1.GetNodeAt((int)lp2->x1 + 1, (int)lp2->y1 + 1); x1 = lp2->x1 + node.Bounds.X + node.Bounds.Width + 5; y1 = lp2->y1; strText = "( " + node.Nodes.Count.ToString() + " )"; //Nodeの子ノード数をNodeの後ろに青で表示する g.DrawString(strText, TreeView1.Font, System.Drawing.Brushes.Blue, x1, y1, System.Drawing.StringFormat.GenericTypographic); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ただしこの方法では、ノードの末尾に文字列を描画しているだけなの で、水平スクロールバーが表示される時(あるいは表示されるべき時) にこの文字列の長さは考慮されないため、スクロールさせても表示さ れなくなる「可能性があります。 ○この記事の基になった掲示板のスレッド [題名] TreeViewのテキスト表示部分の右 [投稿者(敬称略)] edacho, 管理人, よねKEN [URL] http://dobon.net/vb/bbs/log3-2/717.html ─────────────────────────────── ■コンピュータ雑学 ─────────────────────────────── 最近巷では「トリビアの泉」や「うんちく王」の影響でか、雑学ブー ムであるらしいです。生ぬるい雑学を得意げに披露されると非常に腹 立たしいものですが、ここではこのような人に話すと嫌われるであろ うコンピュータに関する雑学を紹介していこうかなと考えています(今 回限りという可能性も大いにありますが)。.NETとは関係ありません が、息抜きにどうぞ。 ●「C言語」の「C」の意味は? C言語は、1973年頃AT&Tベル研究所でデニス・リッチー氏らにより、 UNIXのために開発されたプログラミング言語です。同AT&Tベル研究所 のケン・トンプソンらにより開発されたB言語の後続という意味で、「C 言語」と名づけられましたので、「C」は何かの略ということではあり ません。 [URL]The Development of the C Language http://cm.bell-labs.com/cm/cs/who/dmr/chist.html それではB言語の前にA言語があったのかというと、そうではありませ んが、B言語の元をたどると「ALGOL 60」となるため(そのまえに BCPL、CPLがありますが)、うまい具合に「ABC」と並びます。 そうなると次は「D」ですが、「D言語」は現在開発中で、そこそこ知 られています。 [URL]D Programming Language http://www.digitalmars.com/d/index.html さらに調べてみたところ、E、F、G(National Instruments Labviewの graphical programming language)、Hと見つかりました。Iに関して は見つかりませんでしたが、ちゃんと探せばあるかもしれません。 [URL]The E Language http://www.erights.org/elang/index.html [URL]F Programming Language Homepage http://www.fortran.com/F/ [URL]National Instruments http://www.ni.com/ [URL]The H - Language. A small functional programming Language. http://www.inf.ufrgs.br/~dubois/fbeans/hlang.html =============================== ■このマガジンの購読、購読中止、バックナンバー、説明に関しては  次のページをご覧ください。  http://www.mag2.com/m/0000104516.htm ■発行人・編集人:どぼん!  (Microsoft MVP for Visual Basic, Oct 2003-Oct 2004)  http://dobon.net  dobon_info@yahoo.co.jp ■ご質問等はメールではなく、掲示板へお願いいたします。  http://dobon.net/vb/bbs.html ■上記メールアドレスへのメールは確実に読まれる保障はありません  (スパム、ウィルス対策です)。メールは下記URLのフォームメール  から送信してください。  http://dobon.net/mail.html Copyright (c) 2003 - 2004 DOBON! All rights reserved. ===============================