#title(.NETプログラミング研究 第37号) #navi(.NET プログラミング研究) #contents *.NETプログラミング研究 第37号 [#sfa919ae] **.NET質問箱 [#y06cac1c] 「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、Q&A形式にまとめて紹介します。 -[[どぼん!のプログラミング掲示板>http://dobon.net/vb/bbs.html]] *** 拡張子に関連付けられた実行ファイルのパスを取得するには? [#vb60c9c0] #column(注意){{ この記事の最新版は「[[拡張子に関連付けられた実行ファイルのパスを取得する>http://dobon.net/vb/dotnet/system/findassociatedexe.html]]」で公開しています。 }} ''【質問】'' あるファイルの拡張子に関連付けられている実行ファイルのフルパスを取得するには、どのようにすればよいでしょうか? ''【回答】'' まず、Win32 APIのFindExecutable関数を使う方法が考えられます。 -[[プラットフォーム SDK FindExecutable>http://www.microsoft.com/japan/msdn/library/ja/jpshell/html/_win32_findexecutable.asp]] この場合、次のようなコードで実行ファイルのパスを取得できます。 #code(vbnet){{ Class MainClass <System.Runtime.InteropServices.DllImport("shell32.dll")> _ Public Shared Function FindExecutable(ByVal lpFile As String, _ ByVal lpDirectory As String, _ ByVal lpResult As System.Text.StringBuilder) As Integer End Function '/ <summary> '/ エントリポイントです。 '/ </summary> Public Shared Sub Main() '関連付けられた実行ファイルを取得するファイル名 Dim fileName As String = "C:\test.txt" '結果を受け取るためのStringBuilderオブジェクト Dim exePath As New System.Text.StringBuilder(255) 'fileNameに関連付けられた実行ファイルのパスを取得する If FindExecutable(fileName, Nothing, exePath) > 32 Then '成功した時は、exePathの内容を表示する Console.WriteLine(exePath.ToString()) Else Console.WriteLine("失敗しました。") End If End Sub End Class }} #code(csharp){{ class MainClass { [System.Runtime.InteropServices.DllImport("shell32.dll")] public static extern int FindExecutable( string lpFile, string lpDirectory, System.Text.StringBuilder lpResult); /// <summary> /// エントリポイントです。 /// </summary> public static void Main() { //関連付けられた実行ファイルを取得するファイル名 string fileName = "C:\\test.txt"; //結果を受け取るためのStringBuilderオブジェクト System.Text.StringBuilder exePath = new System.Text.StringBuilder(255); //fileNameに関連付けられた実行ファイルのパスを取得する if (FindExecutable(fileName, null, exePath) > 32) { //成功した時は、exePathの内容を表示する Console.WriteLine(exePath.ToString()); } else { Console.WriteLine("失敗しました。"); } } } }} しかし残念ながらFindExecutableには、関連付けられた実行ファイルのパスにスペース文字が含まれる時、はじめのスペースがnull文字で置き換えられてしまうというバグがあります。このために、例えば実行ファイルのパスが、 C:\Program Files\Microsoft Office\WINWORD.EXE であった場合、FindExecutableは、 C:\Program という文字列を返したかのようになってしまいます。 -[[マイクロソフト サポート技術情報 - 140724: PRB: FindExecutable() Truncates Result at First Space in LFN>http://support.microsoft.com/?kbid=140724]] FindExecutableのようなWin32 APIを使用しなくても、拡張子の関連付けに関する情報はレジストリに保存されていますので、レジストリを調べれば拡張子に関連付けられた実行ファイルのパスは分かります。 拡張子の関連付けに関する情報は、レジストリのHKEY_CLASS_ROOTにあります。具体的には、"HKEY_CLASS_ROOT\(拡張子)"というキーにその拡張子に関連付けられているファイルタイプ名が格納されており、"HKEY_CLASS_ROOT\(ファイルタイプ名)\shell\(openなどのアクション名)\command"というキーに実行ファイルのパス(コマンドライン引数を含む)が格納されています。 レジストリを調べて拡張子に関連付けられた実行ファイルのパスを取得するコードの例を示します。ここでは実行ファイルのパスだけでなく、コマンドライン引数が付いたまま返しています(つまり、「アクションを実行するアプリケーション」で指定されている文字列をそのまま返します)。 #code(vbnet){{ '/ <summary> '/ ファイルに関連付けられた実行ファイルのパスを取得する '/ </summary> '/ <param name="fileName">関連付けを調べるファイル</param> '/ <param name="extra">アクション(open,print,editなど)</param> '/ <returns>実行ファイルのパス + コマンドライン引数</returns> Public Shared Function FindAssociatedExecutableFile( _ ByVal fileName As String, ByVal extra As String) As String '拡張子を取得 Dim extName As String = System.IO.Path.GetExtension(fileName) 'ファイルタイプを取得 Dim regKey As Microsoft.Win32.RegistryKey = _ Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(extName) If regKey Is Nothing Then Throw New Exception("見つかりませんでした。") End If Dim fileType As String = CStr(regKey.GetValue("")) regKey.Close() '「アクションを実行するアプリケーション」を取得 Dim regKey2 As Microsoft.Win32.RegistryKey = _ Microsoft.Win32.Registry.ClassesRoot.OpenSubKey( _ String.Format("{0}\shell\{1}\command", fileType, extra)) If regKey2 Is Nothing Then Throw New Exception("見つかりませんでした。") End If Dim command As String = CStr(regKey2.GetValue("")) regKey2.Close() Return command End Function '/ <summary> '/ ファイルに関連付けられた実行ファイルのパスを取得する '/ </summary> '/ <param name="fileName">関連付けを調べるファイル</param> '/ <returns>実行ファイルのパス + コマンドライン引数</returns> Public Shared Function FindAssociatedExecutableFile( _ ByVal fileName As String) As String Return FindAssociatedExecutableFile(fileName, "open") End Function }} #code(csharp){{ /// <summary> /// ファイルに関連付けられた実行ファイルのパスを取得する /// </summary> /// <param name="fileName">関連付けを調べるファイル</param> /// <param name="extra">アクション(open,print,editなど)</param> /// <returns>実行ファイルのパス + コマンドライン引数</returns> public static string FindAssociatedExecutableFile( string fileName, string extra) { //拡張子を取得 string extName = System.IO.Path.GetExtension(fileName); //ファイルタイプを取得 Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(extName); if (regKey == null) throw new Exception("見つかりませんでした。"); string fileType = (string) regKey.GetValue(""); regKey.Close(); //「アクションを実行するアプリケーション」を取得 Microsoft.Win32.RegistryKey regKey2 = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey( string.Format(@"{0}\shell\{1}\command", fileType, extra)); if (regKey2 == null) throw new Exception("見つかりませんでした。"); string command = (string) regKey2.GetValue(""); regKey2.Close(); return command; } /// <summary> /// ファイルに関連付けられた実行ファイルのパスを取得する /// </summary> /// <param name="fileName">関連付けを調べるファイル</param> /// <returns>実行ファイルのパス + コマンドライン引数</returns> public static string FindAssociatedExecutableFile( string fileName) { return FindAssociatedExecutableFile(fileName, "open"); } }} 拡張子に関連付けられている実行可能ファイルパスを取得するためのAPIには、AssocQueryString関数もあります。これを使用するには、Internet Explorer 5以上が必要となります。詳しくは次のリンク先をご覧ください。 -[[AssocQueryString Function>http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/registry/assocquerystring.asp]] ○この記事の基になった掲示板のスレッド -[[関連付けられている実行可能ファイルパスの取得: 投稿者(敬称略) riki, 管理人, ピラルク>http://dobon.net/vb/bbs/log3-2/721.html]] ***ピクチャボックスに表示されている画像をドラッグ&ドロップする [#l2fa7453] #column(注意){{ この記事の最新版は「[[ピクチャボックスに表示されている画像をドラッグ&ドロップする>http://dobon.net/vb/dotnet/graphics/pictureboxdragdrop.html]]」で公開しています。 }} ''【質問】'' ピクチャボックスに表示されている画像をワードパッドやWordなどのアプリケーションにドラッグ&ドロップしてデータを渡したいのですが、どのようにすればよいでしょうか? ''【回答】'' ドラッグ&ドロップの操作を開始するには、コントロールのDoDragDropメソッドを使いますが、ワードパッドやWordにドラッグ&ドロップでデータを渡す場合は、DoDragDropメソッドのドラッグするデータに画像のImageオブジェクトやBitmapオブジェクトをそのまま指定するだけで大丈夫のようです。なお、ドラッグ&ドロップの基本的な方法については、「ドラッグ&ドロップを行う」をご覧ください。 -[[ドラッグ&ドロップを行う>http://dobon.net/vb/dotnet/control/draganddrop.html]] 例えば、ピクチャボックス"PictureBox1"のImageプロパティに設定されている画像をドラッグするためのコードは、次のようになります。(ここではPictureBox1のMouseDownイベントハンドラPictureBox1_MouseDownでドラッグを開始しています。) #code(vbnet){{ Private Sub PictureBox1_MouseDown(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles PictureBox1.MouseDown 'ドラッグを開始する PictureBox1.DoDragDrop(PictureBox1.Image, DragDropEffects.All) End Sub }} #code(csharp){{ private void PictureBox1_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e) { //ドラッグを開始する PictureBox1.DoDragDrop(PictureBox1.Image, DragDropEffects.All); } }} さらに、画像をアプリケーションにドロップしたときに、画像のイメージに加えさらに画像ファイルのデータを渡すための方法がニュースグループの次のスレッドに投稿されています。 -[[Newsgroups:microsoft.public.dotnet.framework.windowsforms: How do I drag images from my app and drop them as files in explorer?>http://groups.google.co.jp/groups?hl=ja&lr=&ie=UTF-8&inlang=ja&threadm=en1LqODACHA.1340%40tkmsftngp02]] この方法によると、まずピクチャボックスに表示されている画像がファイルに保存されていない時はこれをファイルに保存してから、DataObjectオブジェクトのSetDataにより画像ファイルのパスとイメージを格納し、DoDragDropメソッドによりドラッグを行うというものです。 次にこの方法を使った例を示します。前と同様にピクチャボックス"PictureBox1"のImageプロパティに設定されている画像をドラッグするものとし、この画像はすでに"C:\temp.bmp"というファイルに保存されているものとします。画像が保存されていない場合は、あらかじめSaveメソッドにより保存するようにしてください。 #code(vbnet){{ Private Sub PictureBox1_MouseDown(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles PictureBox1.MouseDown '画像ファイル名の入ったstring型配列を作る Dim fileNames As String() = {"c:\temp.bmp"} 'ファイルドロップ形式でDataObjectオブジェクトを作成する Dim dataObj As New DataObject(DataFormats.FileDrop, fileNames) 'さらにビットマップ形式でも格納する dataObj.SetData(DataFormats.Bitmap, Image.FromFile(fileNames(0))) 'ドラッグを開始する PictureBox1.DoDragDrop(dataObj, DragDropEffects.All) End Sub }} #code(csharp){{ private void PictureBox1_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e) { //画像ファイル名の入ったstring型配列を作る string[] fileNames = {"c:\\temp.bmp"}; //ファイルドロップ形式でDataObjectオブジェクトを作成する DataObject dataObj = new DataObject(DataFormats.FileDrop, fileNames); //さらにビットマップ形式でも格納する dataObj.SetData( DataFormats.Bitmap, Image.FromFile(fileNames[0])); //ドラッグを開始する PictureBox1.DoDragDrop(dataObj,DragDropEffects.All); } }} この方法でドラッグ&ドロップした場合、ドロップ先がエクスプローラである場合はもちろん、ワードパッドなど多くのアプリケーションへのドロップでも単にファイルのドロップとして扱われてしまうようです。 ○この記事の基になった掲示板のスレッド -[[ドラッグ&ドロップについて。: 投稿者(敬称略) どんちゃん, ピラルク>http://dobon.net/vb/bbs/log3-2/740.html]] ***DataGridにLinkLabelを表示するには? [#v3fe5aee] #column(注意){{ この記事の最新版は「[[DataGridにLinkLabelを表示する>http://dobon.net/vb/dotnet/datagrid/datagridlinklabel.html]]」で公開しています。 }} ''【質問】'' System.Windows.Forms.DataGridコントロールにLinkLabelを表示して、ハイパーリンクがはられているようにしたいのですが、どのようにすればよいでしょうか? ''【回答】'' DataGridColumnStyleクラスから派生した新しいクラスを作成することにより実現させる方法が適当だと思いますが、問題はどのようにLinkLabelを表示するかという点でしょう。 一番簡単で分かりやすいのは、DataGridColumnStyleクラスのEditメソッドでLinkLabelコントロールを表示するという方法です。ピラルクさんが掲示板に投稿していただいた方法や、ニュースグループ「microsoft.public.dotnet.framework.windowsforms」に投稿されたTravis Merkelさんの方法がこれです。DOBON.NET .NET Tipsで紹介している「DataGridでComboBoxを使う」のComboBoxをLinkLabelにそのまま代えたという感じです。 -[[microsoft.public.dotnet.framework.windowsforms: RE: How do you add a hyperlink to a datagrid?>http://groups.google.co.jp/groups?hl=ja&lr=&ie=UTF-8&inlang=ja&selm=B9FD3364-D395-404E-9744-E9DE08114FC7%40microsoft.com]] -[[DataGridでComboBoxを使う>http://dobon.net/vb/dotnet/datagrid/datagridcombobox.html]] この方法はEditメソッドでLinkLabelを表示しているため、セルがアクティブになってからLinkLabelが表示され、はじめからLinkLabelが表示されるわけではありません。 この方法を使った簡単なサンプルを下に示します(かなりの手抜きです)。ここでは、LinkLabelをクリックすると、セルに表示されている文字列をProcess.Startメソッドに渡して呼び出しています。なお、DataGridColumnStyleクラスの使用法に関しては、「DataGridの列の幅を変更する」をご覧ください。 -[[DataGridの列の幅を変更する>http://dobon.net/vb/dotnet/datagrid/columnwidth.html]] #code(vbnet){{ Imports System Imports System.Data Imports System.Drawing Imports System.Windows.Forms Namespace Dobon.Samples.Forms '/ <summary> '/ DataGridにLinkLabelを表示するDataGridColumnStyle '/ </summary> Public Class DataGridLinkLabelColumn Inherits DataGridTextBoxColumn 'TextBoxの代わりに表示するLinkLabel Private _linkLabel As LinkLabel Public ReadOnly Property LinkLabel() As LinkLabel Get Return _linkLabel End Get End Property Public Sub New() _linkLabel = New LinkLabel AddHandler _linkLabel.Click, AddressOf _linkLabel_Click End Sub Protected Overloads Overrides Sub Edit( _ ByVal source As System.Windows.Forms.CurrencyManager, _ ByVal rowNum As Integer, _ ByVal bounds As System.Drawing.Rectangle, _ ByVal [readOnly] As Boolean, _ ByVal instantText As String, _ ByVal cellIsVisible As Boolean) MyBase.Edit(source, rowNum, bounds, [readOnly], _ instantText, cellIsVisible) 'TextBoxの代わりにLinkLabelを表示する TextBox.Visible = False _linkLabel.Parent = TextBox.Parent _linkLabel.Bounds = bounds _linkLabel.Text = TextBox.Text _linkLabel.Visible = True _linkLabel.BringToFront() _linkLabel.Focus() End Sub Private Sub _linkLabel_Click( _ ByVal sender As Object, ByVal e As EventArgs) 'LinkLabelがクリックされた時は表示されているTextを実行する Dim link As LinkLabel = CType(sender, LinkLabel) System.Diagnostics.Process.Start(link.Text) End Sub End Class End Namespace }} #code(csharp){{ using System; using System.Data; using System.Drawing; using System.Windows.Forms; namespace Dobon.Samples.Forms { /// <summary> /// DataGridにLinkLabelを表示するDataGridColumnStyle /// </summary> public class DataGridLinkLabelColumn : DataGridTextBoxColumn { //TextBoxの代わりに表示するLinkLabel private LinkLabel _linkLabel; public LinkLabel LinkLabel { get {return _linkLabel;} } public DataGridLinkLabelColumn() { _linkLabel = new LinkLabel(); _linkLabel.Click += new EventHandler(_linkLabel_Click); } protected override void Edit( CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible) { base.Edit(source, rowNum, bounds, readOnly, instantText, cellIsVisible); //TextBoxの代わりにLinkLabelを表示する TextBox.Visible = false; _linkLabel.Parent = TextBox.Parent; _linkLabel.Bounds = bounds; _linkLabel.Text = TextBox.Text; _linkLabel.Visible = true; _linkLabel.BringToFront(); _linkLabel.Focus(); } private void _linkLabel_Click(object sender, EventArgs e) { //LinkLabelがクリックされた時は表示されているTextを実行する LinkLabel link = (LinkLabel) sender; System.Diagnostics.Process.Start(link.Text); } } } }} アクティブなセルだけでなく、すべての行にLinkLabelを表示するには、Paintメソッドで何らかの処理を行う必要があります。具体的には、必要な数だけLinkLabelコントロールを作成するか、あたかもLinkLabelコントロールのように文字列を描画するかということになるでしょう。 必要な数だけLinkLabelコントロールを作成する例が、ニュースグループ「microsoft.public.dotnet.framework.windowsforms.controls」に投稿されています。 -[[microsoft.public.dotnet.framework.windowsforms.controls: Re: DataGrid: How to get hyperlinks?: From:developers>http://groups.google.co.jp/groups?hl=ja&lr=&ie=UTF-8&inlang=ja&selm=u29LLDsVDHA.2252%40TK2MSFTNGP10.phx.gbl]] この方法は、LinkLabelコントロールを行ごとにHashtableに保存しておき、Paintメソッドで必要に応じて配置するというものです。行ごとにLinkLabelコントロールを作成しているため、行が多くなると、かなりメモリを消費するでしょう。 それが嫌であれば、PaintメソッドでLinkLabelのような文字列を描画すればよいということになります。ここで問題なのは、どうやってクリックされたことを知るかということです。そのためには、例えばDataGridのMouseUpイベントでHitTestInfoメソッドを使ってセル上でマウスボタンが押されたか判断するという方法があります。LinkLabelの動作とはかなり違いますが、仕方のないところでしょう。 以下にPaintメソッドで文字列を描画するDataGridColumnStyleの簡単な例を示します。ここでは、DataGridのMouseMoveイベントでマウスがセル上にあるか調べ、そうであればマウスカーソルをハンドカーソルに変更しています。また、DataGridのMouseUpイベントでクリックされたことにしています。 #code(vbnet){{ Namespace Dobon.Samples.Forms '/ <summary> '/ DataGridにLinkLabelを表示するDataGridColumnStyle '/ </summary> Public Class DataGridLinkLabelColumn2 Inherits DataGridTextBoxColumn Private _margin As New Point(1, 2) Private _visitedLinks As System.Collections.ArrayList Private _dataGrid As DataGrid Public Sub New() _visitedLinks = New System.Collections.ArrayList End Sub Protected Overloads Overrides Sub Edit( _ ByVal [source] As CurrencyManager, _ ByVal rowNum As Integer, _ ByVal bounds As Rectangle, _ ByVal [readOnly] As Boolean, _ ByVal instantText As String, _ ByVal cellIsVisible As Boolean) End Sub '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 textBrush As Brush If _visitedLinks.Contains([text]) Then textBrush = Brushes.Purple Else textBrush = Brushes.Blue End If 'フォントにアンダーラインをつける Dim textFont As New Font( _ DataGridTableStyle.DataGrid.Font.FontFamily, _ DataGridTableStyle.DataGrid.Font.Size, _ DataGridTableStyle.DataGrid.Font.Style _ Or FontStyle.Underline) Dim rectf As New RectangleF( _ bounds.X, bounds.Y, bounds.Width, bounds.Height) rectf.Inflate(-_margin.X, -_margin.Y) '文字列を描画する g.DrawString([text], textFont, textBrush, rectf, sf) sf.Dispose() textFont.Dispose() End Sub Protected Overrides Sub SetDataGridInColumn( _ ByVal value As DataGrid) MyBase.SetDataGridInColumn(value) AddHandler value.MouseMove, AddressOf DataGrid_MouseMove AddHandler value.MouseUp, AddressOf DataGrid_MouseUp _dataGrid = value End Sub Protected Overloads Overrides Sub Dispose( _ ByVal disposing As Boolean) MyBase.Dispose(disposing) RemoveHandler _dataGrid.MouseMove, _ AddressOf DataGrid_MouseMove RemoveHandler _dataGrid.MouseUp, _ AddressOf DataGrid_MouseUp End Sub Private Sub DataGrid_MouseMove( _ ByVal sender As Object, ByVal e As MouseEventArgs) 'マウスがセル上にあるときは、カーソルを変更する Dim hti As DataGrid.HitTestInfo = _ DataGridTableStyle.DataGrid.HitTest(e.X, e.Y) If hti.Type = DataGrid.HitTestType.Cell And _ hti.Column = _ DataGridTableStyle.GridColumnStyles.IndexOf(Me) Then DataGridTableStyle.DataGrid.Parent.Cursor = _ Cursors.Hand Else DataGridTableStyle.DataGrid.Parent.Cursor = _ Cursors.Default End If End Sub Private Sub DataGrid_MouseUp( _ ByVal sender As Object, ByVal e As MouseEventArgs) Dim grid As DataGrid = DataGridTableStyle.DataGrid Dim info As DataGrid.HitTestInfo = grid.HitTest(e.X, e.Y) 'マウスがセル上にあるか調べる If info.Type = DataGrid.HitTestType.Cell And info.Column = _ DataGridTableStyle.GridColumnStyles.IndexOf(Me) Then 'Process.Startを呼び出す Dim cm As CurrencyManager = _ CType(grid.BindingContext( _ grid.DataSource, grid.DataMember), CurrencyManager) Dim str As String = _ GetColumnValueAtRow(cm, info.Row).ToString() System.Diagnostics.Process.Start(str) '訪れたことを記憶する _visitedLinks.Add(str) End If End Sub End Class End Namespace }} #code(csharp){{ namespace Dobon.Samples.Forms { /// <summary> /// DataGridにLinkLabelを表示するDataGridColumnStyle /// </summary> public class DataGridLinkLabelColumn2 : DataGridTextBoxColumn { Point _margin = new Point(1, 2); private System.Collections.ArrayList _visitedLinks; DataGrid _dataGrid; public DataGridLinkLabelColumn2() { _visitedLinks = new System.Collections.ArrayList(); } protected override void Edit( CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible) { } //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); //前景色を決める Brush textBrush; if (_visitedLinks.Contains(text)) textBrush = Brushes.Purple; else textBrush = Brushes.Blue; //フォントにアンダーラインをつける Font textFont = new Font(DataGridTableStyle.DataGrid.Font.FontFamily, DataGridTableStyle.DataGrid.Font.Size, DataGridTableStyle.DataGrid.Font.Style | FontStyle.Underline); RectangleF rectf = new RectangleF( bounds.X, bounds.Y, bounds.Width, bounds.Height); rectf.Inflate(-_margin.X, -_margin.Y); //文字列を描画する g.DrawString(text, textFont, textBrush, rectf, sf); sf.Dispose(); textFont.Dispose(); } protected override void SetDataGridInColumn(DataGrid value) { base.SetDataGridInColumn(value); value.MouseMove += new MouseEventHandler(DataGrid_MouseMove); value.MouseUp += new MouseEventHandler(DataGrid_MouseUp); _dataGrid = value; } protected override void Dispose(bool disposing) { base.Dispose(disposing); _dataGrid.MouseMove -= new MouseEventHandler(DataGrid_MouseMove); _dataGrid.MouseUp -= new MouseEventHandler(DataGrid_MouseUp); } private void DataGrid_MouseMove( object sender, MouseEventArgs e) { //マウスがセル上にあるときは、カーソルを変更する DataGrid.HitTestInfo hti = DataGridTableStyle.DataGrid.HitTest(e.X, e.Y); if (hti.Type == DataGrid.HitTestType.Cell && hti.Column == DataGridTableStyle.GridColumnStyles.IndexOf(this)) DataGridTableStyle.DataGrid.Parent.Cursor = Cursors.Hand; else DataGridTableStyle.DataGrid.Parent.Cursor = Cursors.Default; } private void DataGrid_MouseUp(object sender, MouseEventArgs e) { DataGrid grid = DataGridTableStyle.DataGrid; DataGrid.HitTestInfo info = grid.HitTest(e.X, e.Y); //マウスがセル上にあるか調べる if (info.Type == DataGrid.HitTestType.Cell && info.Column == DataGridTableStyle.GridColumnStyles.IndexOf(this)) { //Process.Startを呼び出す CurrencyManager cm = (CurrencyManager) grid.BindingContext[ grid.DataSource, grid.DataMember]; string str = GetColumnValueAtRow(cm, info.Row).ToString(); System.Diagnostics.Process.Start(str); //訪れたことを記憶する _visitedLinks.Add(str); } } } } }} これらの方法に不満があるならば、市販品を使うのがよいでしょう。LinkLabelを表示できるフリーのライブラリはほとんど見かけませんが、「Extended DataGrid」というものがあります。 -[[Extended DataGrid>http://dotnet.leadit.be/extendeddatagrid/]] ○この記事の基になった掲示板のスレッド -[[DataGridのプロパティ変更)お願いします: 投稿者(敬称略) 晋作, fuku, 管理人, ピラルク>http://dobon.net/vb/bbs/log3-2/934.html]] **コンピュータ雑学 [#d1ac873e] ここでは、話すと人に嫌われるなまぬるいコンピュータに関する雑学 を紹介します。 ***Windows NTの「NT」の意味は? [#t99112c5] Microsoft Windows NTの「NT」の意味に関して、Microsoftは公式にはなんら言及をしていないようですが、Microsoftのいくつかの発行物では、「New Technology」の略で「NT」と説明されているようです。 しかし広く信じられている説には、別のものがあります。それは、「Windows NTの父」と呼ばれるDave CutlerがMicrosoftに来る前にDEC社で開発したOS、VMSのそれぞれのアルファベットを次の文字に進めた「WNT」から由来しているというものです。しかし、Windows NTははじめ「NT OS/2」と呼ばれていたことを考慮すると、この説はただの冗談であるように思われます。 さらには、Windows & .NET Magazine Networkの「WinInfo Daily UPDATE, January 24, 2003」によると、Windows NTの開発者の一人であるMark Lucovskyが「NT」の意味について、開発にi860のエミュレータである「N10」を使っていたため、「N-Ten」で動くことから「NT」と名づけたと明かしています。 -[[Windows & .NET Magazine Network: WinInfo Daily UPDATE, January 24, 2003>http://www.winnetmag.com/Article/ArticleID/37778/37778.html]] -[[Paul Thurrott's SuperSite for Windows: Windows Server 2003: The Road To Gold, Part One: The Early Years>http://www.winsupersite.com/reviews/winserver2k3_gold1.asp]] 一体どれが真実でどれがただの噂話(あるいは冗談)なのか、本当のところは誰にも分からないのかもしれませんね。 **コメント [#nf1a4bfa] #comment //これより下は編集しないでください #pageinfo([[:Category/.NET]],2004-07-14 (水) 06:00:00,DOBON!,2010-03-21 (日) 02:33:20,DOBON!) |