┏第64号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ──<メニュー>─────────────────────── ■.NET質問箱 ・DataGridコントロールをスクロールさせた時に、別のDataGridを  同時にスクロールさせる ・DataGridを印刷する ・単位を変更して描画する ・VB6のScaleHeight、ScaleWidthプロパティに代わるものは? ─────────────────────────────── ─────────────────────────────── ■.NET質問箱 ─────────────────────────────── 「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込 まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、 Q&A形式にまとめて紹介します。 [URL]どぼん!のプログラミング掲示板 http://dobon.net/vb/bbs.html ─────────────────────────────── ●DataGridコントロールをスクロールさせた時に、別のDataGridを同 時にスクロールさせる 【質問】 System.Windows.Forms.DataGridコントロールを垂直方向にスクロー ルした時に、別のDataGridも同時にスクロールされるようにしたいの ですが、どのようにすればよいのでしょうか? 【回答】 まずDataGridコントロールが垂直方向にスクロールされたことを知る には、Scrollイベントを捕捉したり、プロテクトメンバの GridVScrolledメソッドをオーバーライドしたり、同じくプロテクト メンバのVertScrollBarプロパティのScrollイベントを捕捉したりす る方法があります。 GridVScrolledメソッドやVertScrollBarプロパティのScrollイベント を捕捉する場合は、注意が必要です。これらは、マウスのホイールを 使ったスクロールや、カーソルキーによるスクロールには反応しませ ん。よって、これらによるスクロールにも対応するためには、 MouseWheelイベントなどの別の方法も併用する必要があります。 また、DataGridを指定した行までスクロールさせるには、「DataGrid 内の指定された行までスクロールする」で紹介している方法が使えま す。 [URL]DOBON.NET .NET Tips - DataGrid内の指定された行までスクロー ルする http://dobon.net/vb/dotnet/datagrid/gridvscrolled.html 以下に同時スクロールを可能にするDataGridの例を示します。ここで はScrollイベントによりDataGridがスクロールされたことを感知して います。GridVScrolledメソッドを使った例に関しては、この記事の 最後に示す掲示板のログをご覧ください。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ''' ''' 同時スクロールを可能にするDataGrid ''' Public Class MyDataGrid Inherits DataGrid Public Sub New() AddHandler Me.Scroll, AddressOf MyDataGrid_Scroll End Sub Private _syncScrollGrid As MyDataGrid = Nothing ''' ''' 同時にスクロールさせるDataGrid ''' Public Property SyncScrollGrid() As MyDataGrid Get Return _syncScrollGrid End Get Set(ByVal Value As MyDataGrid) If Not _syncScrollGrid Is Me Then _syncScrollGrid = Value Else Throw New ApplicationException("自分自身に設定できません。") End If End Set End Property ''' ''' 指定した位置までスクロールさせる ''' ''' この行までスクロールする Public Sub SetTopRow(ByVal rowNum As Integer) Dim args As New ScrollEventArgs(ScrollEventType.LargeIncrement, rowNum) MyBase.GridVScrolled(Me, args) End Sub Private Sub MyDataGrid_Scroll(ByVal sender As Object, ByVal e As EventArgs) If Not (_syncScrollGrid Is Nothing) Then '指定位置までスクロール _syncScrollGrid.SetTopRow(VertScrollBar.Value) End If 'フォーカスが別のコントロールに移動しないようにする Me.Focus() End Sub End Class ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ /// /// 同時スクロールを可能にするDataGrid /// public class MyDataGrid : DataGrid { public MyDataGrid() : base() { this.Scroll += new EventHandler(MyDataGrid_Scroll); } private MyDataGrid _syncScrollGrid = null; /// /// 同時にスクロールさせるDataGrid /// public MyDataGrid SyncScrollGrid { get { return _syncScrollGrid; } set { if (_syncScrollGrid != this) { _syncScrollGrid = value; } else { throw new ApplicationException("自分自身に設定できません。"); } } } /// /// 指定した位置までスクロールさせる /// /// この行までスクロールする public void SetTopRow(int rowNum) { ScrollEventArgs args = new ScrollEventArgs(ScrollEventType.LargeIncrement, rowNum); base.GridVScrolled(this, args); } private void MyDataGrid_Scroll(object sender, EventArgs e) { if (_syncScrollGrid != null) { //指定位置までスクロール _syncScrollGrid.SetTopRow(VertScrollBar.Value); } //フォーカスが別のコントロールに移動しないようにする this.Focus(); } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ このクラスを使用するには、DataGridコントロールをこのMyDataGrid に置き換えます。ユーザーがスクロールするDataGridと、そのスクロー ルと同時にスクロールさせたいDataGridの両方にMyDataGridを使用し ます。そして、ユーザーがスクロールするMyDataGridの SyncScrollGridプロパティに、同時にスクロールさせたいMyDataGrid を指定します。なお両者のMyDataGridの行数は必ず同じにしてくださ い。 ○この記事の基になった掲示板のスレッド [題名] DataGridの同期 [投稿者(敬称略)] おくら, NowhereMan [URL] http://dobon.net/vb/bbs/log3-7/3992.html [題名] データグリッドでの画面分割 [投稿者(敬称略)] nepia [URL] http://dobon.net/vb/bbs/log3-7/4041.html [題名] スクロールの同期、または抑止 [投稿者(敬称略)] nepia, NowhereMan [URL] http://dobon.net/vb/bbs/log3-7/4150.html [題名] string "ff"を数値型の 255 に変換したい [投稿者(敬称略)] blessyou, 深山, nepia [URL] http://dobon.net/vb/bbs/log3-8/4873.html ─────────────────────────────── ●DataGridを印刷する 【質問】 System.Windows.Forms.DataGridコントロールに表示されているデー タを印刷することはできますか? 【回答】 MSDNにそのものズバリの「コード : DataGrid の印刷」という例が紹 介されています。しかしこれらは残念ながら表示されている範囲のみ しか印刷できず、それ以外を印刷するには、適当な位置までスクロー ルして印刷するという処理を繰り返す必要があります。しかしそれも 正確に行うのは難いため、この方法は実用的とは言えないでしょう。 [URL]コード : DataGrid の印刷 (Visual C#) http://www.microsoft.com/japan/msdn/library/ja/cscon/html/vclrfCodePrintingDataGridVisualC.asp [URL]コード : データ グリッドを印刷する (Visual Basic) http://www.microsoft.com/japan/msdn/library/ja/dv_vbCode/html/vbtskCodeExamplePrintingDataGrid.asp 実際に良く使われている方法は、DataGridで表示しているデータを自 分で描画して印刷する方法です。この方法はかなり手間がかかります が、自由度が高く、融通が利きます。 ここではその方法を具体的には説明しません。しかし、このようにし てDataGridを印刷するためのクラスは数多く公開されています。以下 にその幾つかを紹介させていただきますので、参考にしてください。 [URL]How to Print a DataGrid in C# and .NET http://www.c-sharpcorner.com/Graphics/DataGridPrinterMG.asp [URL]A class to print and print preview a DataGrid control - The Code Project - VB.NET http://www.codeproject.com/vb/net/datagridprinter.asp [URL]Printing with a custom DataGrid - The Code Project - VB.NET http://www.codeproject.com/vb/net/datagridex.asp [URL]DataGrid Printing Class v1.0b - The Code Project - VB.NET http://www.codeproject.com/vb/net/DataGrid_Printing_Class.asp [URL]DataGrid Printing Class V1.0b - The Code Project - C# Controls http://www.codeproject.com/cs/miscctrl/DataGridPrinter.asp [URL]Print a DataSet's Contents in VB.NET http://www.thescarms.com/dotNet/PrintDataSet.asp [URL]Know Dot Net - Print Contents of Grid or ListView http://www.knowdotnet.com/articles/printgriddemo.html ○この記事の基になった掲示板のスレッド [題名] DataGridの使い方 [投稿者(敬称略)] 満, NowhereMan [URL] http://dobon.net/vb/bbs/log3-7/4044.html [題名] DataGridを印刷するのに [投稿者(敬称略)] ふむ, NowhereMan [URL] http://dobon.net/vb/bbs/log3-7/4272.html ─────────────────────────────── ●単位を変更して描画する 【質問】 メートルやインチ単位の長さを指定して描画や印刷を行いたいのです が、どのようにすればよいのでしょうか? 【回答】 一番簡単な方法は、描画先のGraphicsオブジェクトのPageUnitプロパ ティを変更してから描画するという方法でしょう。 PageUnitプロパティはページ座標で使用する長さの単位を指定するた めのプロパティで、ページ変換(ページ座標からデバイス座標への変 換)で使用されます。GDI+の座標系について詳しくは、MSDNの「座標 系の種類」をご覧ください。 [URL]座標系の種類 http://www.microsoft.com/japan/msdn/library/ja/cpguide/html/_gdiplus_Types_of_Coordinate_Systems_about.asp PageUnitプロパティにはGraphicsUnit列挙体を指定しますが、 GraphicsUnit列挙体には、以下のようなメンバーがあります(MSDNか らの引用です)。つまり、これらの単位を指定できるわけです。 ‥‥▽ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Display 1/75インチを長さの単位に指定します。 Document ドキュメント単位(1/300インチ)を長さの単位に指定します。 Inch インチを長さの単位に指定します。 Millimeter ミリメートルを長さの単位に指定します。 Pixel デバイスピクセルを長さの単位に指定します。 Point プリンタポイント(1/72インチ)を長さの単位に指定します。 World ワールド単位を長さの単位に指定します。 ‥‥△ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ PageUnitプロパティを使った例を以下に示します。ここでは、フォー ムのOnPaintメソッドをオーバーライドすることにより、フォームに 太さ0.1インチで4X2インチの長方形を描画しています。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) MyBase.OnPaint(e) 'Penを用意する Dim redPen As New Pen(Color.Red, 0.1F) 'インチ単位にする e.Graphics.PageUnit = GraphicsUnit.Inch '太さ0.1インチで4X2インチの長方形を描画 e.Graphics.DrawRectangle(redPen, 0.2F, 0.4F, 4, 2) 'Penを破棄 redPen.Dispose() End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); //Penを用意する Pen redPen = new Pen(Color.Red, 0.1f); //インチ単位にする e.Graphics.PageUnit = GraphicsUnit.Inch; //太さ0.1インチで4X2インチの長方形を描画 e.Graphics.DrawRectangle(redPen, 0.2f, 0.4f, 4, 2); //Penを破棄 redPen.Dispose(); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ もし自分で描画する画面のdpi(dots per inch)を取得して、それを 元にピクセル単位の長さを計算できるのであれば、そうすることもで きます。dpiはその名の通り、1インチ内のピクセル数を表し、水平方 向および垂直方向のdpiは、GraphicsクラスのDpiXとDpiYプロパティ で取得することができます。 補足:「HOWTO: How to Make an Application Display Real Units of Measurement」では、GetDeviceCaps関数を使ってdpiを取得する方 法が紹介されています。ちなみにDpiXプロパティはGdipGetDpiX関数 を使っているようです。 [URL]HOWTO: How to Make an Application Display Real Units of Measurement http://support.microsoft.com/kb/127152/ このような方法により、先ほどと同じようにインチ単位で描画する例 を示します。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) MyBase.OnPaint(e) 'Penを用意する Dim redPen As New Pen(Color.Red, 0.1F * e.Graphics.DpiX) '太さ0.1インチで4X2インチの長方形を描画 e.Graphics.DrawRectangle(redPen, _ 0.2F * e.Graphics.DpiX, 0.4F * e.Graphics.DpiX, _ 4 * e.Graphics.DpiX, 2 * e.Graphics.DpiX) 'Penを破棄 redPen.Dispose() End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); //Penを用意する Pen redPen = new Pen(Color.Red, 0.1f * e.Graphics.DpiX); //太さ0.1インチで4X2インチの長方形を描画 e.Graphics.DrawRectangle(redPen, 0.2f * e.Graphics.DpiX, 0.4f * e.Graphics.DpiX, 4 * e.Graphics.DpiX, 2 * e.Graphics.DpiX); //Penを破棄 redPen.Dispose(); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ このように長さをいちいち計算するのが面倒であれば、 ScaleTransformメソッドにより、ワールド変換を使って解決すること もできます。水平方向と垂直方向のdpiが同じであれば、PageScaleプ ロパティにより、ページ変換で行うこともできます。 ScaleTransformメソッドを使った例を以下に示します。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) MyBase.OnPaint(e) 'Penを用意する Dim redPen As New Pen(Color.Red, 0.1F) 'インチ単位にする e.Graphics.ScaleTransform(e.Graphics.DpiX, e.Graphics.DpiY) '太さ0.1インチで4X2インチの長方形を描画 e.Graphics.DrawRectangle(redPen, 0.2F, 0.4F, 4, 2) 'Penを破棄 redPen.Dispose() End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); //Penを用意する Pen redPen = new Pen(Color.Red, 0.1f); //インチ単位にする e.Graphics.ScaleTransform(e.Graphics.DpiX, e.Graphics.DpiY); //太さ0.1インチで4X2インチの長方形を描画 e.Graphics.DrawRectangle(redPen, 0.2f, 0.4f, 4, 2); //Penを破棄 redPen.Dispose(); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ もちろんPageUnitプロパティが使えるならばこのような方法を使う必 要はないと思いますが、PageUnitプロパティで指定できない単位を使 いたい場合はこのような方法が必要になるでしょう。最後に蛇足です が、寸単位で描画する例を示します。ここでは、DpiXとDpiYが同じも のとし、PageScaleプロパティを使っています。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) MyBase.OnPaint(e) 'Penを用意する Dim redPen As New Pen(Color.Red, 0.1F) '寸単位にする(1インチを0.8382寸とする) e.Graphics.PageScale = e.Graphics.DpiX / 0.8382F '太さ0.1寸で4X2寸の長方形を描画 e.Graphics.DrawRectangle(redPen, 0.2F, 0.4F, 4, 2) 'Penを破棄 redPen.Dispose() End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); //Penを用意する Pen redPen = new Pen(Color.Red, 0.1f); //寸単位にする(1インチを0.8382寸とする) e.Graphics.PageScale = e.Graphics.DpiX / 0.8382f; //太さ0.1寸で4X2寸の長方形を描画 e.Graphics.DrawRectangle(redPen, 0.2f, 0.4f, 4, 2); //Penを破棄 redPen.Dispose(); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ○この記事の基になった掲示板のスレッド [題名] 印刷位置をmm単位で指定するには [投稿者(敬称略)] カバチャン, ポン [URL] http://dobon.net/vb/bbs/log3-6/3695.html [題名] Pictrueboxのイメージを縦・横1インチで印刷したい [投稿者(敬称略)] kon, ポン [URL] http://dobon.net/vb/bbs/log3-7/3986.html [題名] 印刷位置の設定について [投稿者(敬称略)] パオ, 管理人, こど。 [URL] http://dobon.net/vb/bbs/log3-4/1972.html [題名] マウスの座標(ミリメートル) [投稿者(敬称略)] れちりん, ant, 管理人 [URL] http://dobon.net/vb/bbs/log3-20/12260.html ─────────────────────────────── ●VB6のScaleHeight、ScaleWidthプロパティに代わるものは? 【質問】 VB6のFormオブジェクトのScaleHeight、ScaleWidthプロパティに代わ るものは、C#やVB.NETでは何ですか? 【回答】 MSDNの「Visual Basic .NET における Form オブジェクトの変更点」 によると、これらに代わるものはありません。ただし、座標の単位が ピクセルの場合は、FormクラスのClientRectangleプロパティや ClientSizeプロパティのHeight、Widthプロパティがその代わりとし て使えます。 [URL]Visual Basic .NET における Form オブジェクトの変更点 http://www.microsoft.com/japan/msdn/library/ja/vbcon/html/vxconchangestoformobjectinvisualbasicnet.asp ただし、コントロールの大きさをフォームの大きさに合わせて変える 目的でScaleHeightとScaleWidthプロパティを使用するのであれば、 DockやAnchorプロパティを使うのがよいでしょう。 MSDNの「ScaleMode がサポートされていない」によると、VB6のコー ドをVS.NETによりアップグレードすると、VB6.TwipsToPixelsXや TwipsToPixelsYを使って単位をtwipからピクセルに変換するようです。 [URL]ScaleMode がサポートされていない http://msdn.microsoft.com/library/ja/vbcon/html/vbup2038.asp なおC#でTwipsToPixelsXやTwipsToPixelsYを使うには、「参照設定」 に「Microsoft.VisualBasic.Compatibility」を追加し、 ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Microsoft.VisualBasic.Compatibility.VB6.Support.TwipsToPixelsX(500) Microsoft.VisualBasic.Compatibility.VB6.Support.TwipsToPixelsY(800) ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ のようにして呼び出します。もしこれらのメソッドを使いたくないの であれば、次のようにしてTwipsPerPixelXとTwipsPerPixelYの値を計 算することもできます。なおここではフォームクラス内に記述するも のとし、フォームのある画面のTwipsPerPixelXとTwipsPerPixelYの値 を計算しています。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Dim g As Graphics = Me.CreateGraphics() Dim TwipsPerPixelX As Single = 1440.0F / g.DpiX Dim TwipsPerPixelY As Single = 1440.0F / g.DpiY g.Dispose() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Graphics g = this.CreateGraphics(); float TwipsPerPixelX = 1440f / g.DpiX; float TwipsPerPixelY = 1440f / g.DpiY; g.Dispose(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ しかしながら、TwipsToPixelsXやTwipsToPixelsYはできるだけ使わな い方が良いでしょう。 ○この記事の基になった掲示板のスレッド [題名] ScaleHeightの使い方 [投稿者(敬称略)] FUM, NowhereMan [URL] http://dobon.net/vb/bbs/log3-7/4017.html [題名] twip→ピクセルに変換する方法 [投稿者(敬称略)] イニ, java.lang.Nullpo [URL] http://dobon.net/vb/bbs/log3-10/5849.html =============================== ■ここで示したコードの多くはまずC#で書き、それを「C# to VB.NET Translator」でVB.NETのコードに変換し、修正を加えたものです。 [URL]C# to VB.NET Translator http://authors.aspalliance.com/aldotnet/examples/translate.aspx ■このマガジンの購読、購読中止、バックナンバー、説明に関しては  次のページをご覧ください。  http://www.mag2.com/m/0000104516.htm ■発行人・編集人:どぼん!  (Microsoft MVP for Visual Basic, Oct 2004-Oct 2005)  http://dobon.net  dobon_info@yahoo.co.jp ■ご質問等はメールではなく、掲示板へお願いいたします。  http://dobon.net/vb/bbs.html ■上記メールアドレスへのメールは確実に読まれる保障はありません  (スパム、ウィルス対策です)。メールは下記URLのフォームメール  から送信してください。  http://dobon.net/mail.html Copyright (c) 2003 - 2006 DOBON! All rights reserved. ===============================