┏第49号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ──<メニュー>─────────────────────── ■ピンポイントリンク ・ZIP書庫の作成、閲覧、展開を行う ■.NET質問箱 ・マルチTIFFやアニメーションGIFに含まれるすべてのイメージを表示するには? ・TextBoxコントロールのEnabledプロパティをFalseにしても前景色と背景色を変えないようにするには? ─────────────────────────────── 明けましておめでとうございます。今年も「.NETプログラミング研究」をよろしくお願いいたします。 ─────────────────────────────── ■ピンポイントリンク ─────────────────────────────── ●ZIP書庫の作成、閲覧、展開を行う ここでは、C#またはVB.NETでZip書庫を扱う(作成、閲覧、展開)方法を紹介します。 C#、VB.NETには標準ではZipを扱う方法が用意されていませんが、J#にはvjslib.dllというものがあり、この中のjava.util.zip名前空間にあるクラスを使うことにより、Zipを扱うことが出来ます。 この方法は、次のURL先で詳しく紹介されています。 [URL]Using the Zip Classes in the J# Class Libraries to Compress Files and Data with C# http://msdn.microsoft.com/msdnmag/issues/03/06/ZipCompression/default.aspx この方法によりZip書庫を扱う具体的なコードを以下に示します。必ずvjslib.dllを参照に加えてください。(後ほど述べますが、現在この方法には多くの問題がありますので、ご注意ください。) まずはZip書庫内のファイル(エントリ)の情報を列挙するコードです。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '作成するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '読み込む Dim fis As New java.io.FileInputStream(zipPath) Dim zis As New java.util.zip.ZipInputStream(fis) 'ZIP内のファイル情報を取得 While True Dim ze As java.util.zip.ZipEntry = zis.getNextEntry() If (ze Is Nothing) Then Exit While End If If Not ze.isDirectory() Then '情報を表示する Console.WriteLine("ファイル名 : {0}", ze.getName()) Console.WriteLine("サイズ : {0} bytes", ze.getSize()) Console.WriteLine("圧縮サイズ : {0} bytes", _ ze.getCompressedSize()) Console.WriteLine("CRC : {0:X}", ze.getCrc()) Dim [date] As New java.util.Date(ze.getTime()) Console.WriteLine("日時 : {0}", [date].ToString()) Console.WriteLine() End If End While '閉じる zis.close() fis.close() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //作成するZIPファイルの設定 string zipPath = "C:\\test.zip"; //読み込む java.io.FileInputStream fis = new java.io.FileInputStream(zipPath); java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(fis); //ZIP内のファイル情報を取得 java.util.zip.ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { if (!ze.isDirectory()) { //情報を表示する Console.WriteLine("ファイル名 : {0}", ze.getName()); Console.WriteLine("サイズ : {0} bytes", ze.getSize()); Console.WriteLine("圧縮サイズ : {0} bytes", ze.getCompressedSize()); Console.WriteLine("CRC : {0:X}", ze.getCrc()); java.util.Date date = new java.util.Date(ze.getTime()); Console.WriteLine("日時 : {0}", date.ToString()); Console.WriteLine(); } } //閉じる zis.close(); fis.close(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 次はZip書庫内のファイルを展開するコードです。ここでは書庫内のすべてのファイルを展開しています。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '展開するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '展開先のフォルダの設定 Dim extractDir As String = "C:\temp" '読み込む Dim fis As New java.io.FileInputStream(zipPath) Dim zis As New java.util.zip.ZipInputStream(fis) 'ZIP内のファイル情報を取得 While True Dim ze As java.util.zip.ZipEntry = zis.getNextEntry() If ze Is Nothing Then Exit While End If If Not ze.isDirectory() Then 'ファイル名 Dim fileName As String = _ System.IO.Path.GetFileName(ze.getName()) '展開先のフォルダ Dim destDir As String = System.IO.Path.Combine( _ extractDir, System.IO.Path.GetDirectoryName(ze.getName())) System.IO.Directory.CreateDirectory(destDir) '展開先のパス Dim destPath As String = _ System.IO.Path.Combine(destDir, fileName) 'FileOutputStreamの作成 Dim fos As New java.io.FileOutputStream(destPath) '書込み Dim buffer(8191) As System.SByte While True Dim len As Integer = zis.read(buffer, 0, buffer.Length) If len <= 0 Then Exit While End If fos.write(buffer, 0, len) End While '閉じる fos.close() End If End While zis.close() fis.close() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //展開するZIPファイルの設定 string zipPath = "C:\\test.zip"; //展開先のフォルダの設定 string extractDir = "C:\\temp"; //読み込む java.io.FileInputStream fis = new java.io.FileInputStream(zipPath); java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(fis); //ZIP内のファイル情報を取得 java.util.zip.ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { if (!ze.isDirectory()) { //ファイル名 string fileName = System.IO.Path.GetFileName(ze.getName()); //展開先のフォルダ string destDir = System.IO.Path.Combine( extractDir, System.IO.Path.GetDirectoryName(ze.getName())); System.IO.Directory.CreateDirectory(destDir); //展開先のパス string destPath = System.IO.Path.Combine(destDir, fileName); //FileOutputStreamの作成 java.io.FileOutputStream fos = new java.io.FileOutputStream(destPath); //書込み sbyte[] buffer = new sbyte[8192]; int len; while ((len = zis.read(buffer, 0, buffer.Length)) > 0) { fos.write(buffer, 0, len); } //閉じる fos.close(); } } zis.close(); fis.close(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 最後は指定したファイルを圧縮してZip書庫を作成するコードです。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '作成するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '圧縮するファイルの設定 Dim filePaths As String() = _ { _ "C:\1.bmp", _ "C:\2.bmp" _ } 'ZipOutputStreamの作成 Dim fos As New java.io.FileOutputStream(zipPath) Dim zos As New java.util.zip.ZipOutputStream(fos) 'Zipにファイルを追加する Dim file As String For Each file In filePaths 'ZIPに追加するときのファイル名を決定する Dim f As String = System.IO.Path.GetFileName(file) 'ディレクトリを保持する時は次のようにする 'Dim f As String = file.Remove( _ ' 0, System.IO.Path.GetPathRoot(file).Length) 'f = f.Replace("\", "/") Dim ze As New java.util.zip.ZipEntry(f) ze.setMethod(java.util.zip.ZipEntry.DEFLATED) zos.putNextEntry(ze) 'FileInputStreamの作成 Dim fis As New java.io.FileInputStream(file) '書込み Dim buffer(8191) As System.SByte While True Dim len As Integer = fis.read(buffer, 0, buffer.Length) If len <= 0 Then Exit While End If zos.write(buffer, 0, len) End While '閉じる fis.close() zos.closeEntry() Next file zos.close() fos.close() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //作成するZIPファイルの設定 string zipPath = "C:\\test.zip"; //圧縮するファイルの設定 string[] filePaths = { "C:\\1.bmp", "C:\\2.bmp" }; //ZipOutputStreamの作成 java.io.FileOutputStream fos = new java.io.FileOutputStream(zipPath); java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(fos); //Zipにファイルを追加する foreach (string file in filePaths) { //ZIPに追加するときのファイル名を決定する string f = System.IO.Path.GetFileName(file); //ディレクトリを保持する時は次のようにする //string f = file.Remove( // 0, System.IO.Path.GetPathRoot(file).Length); //f = f.Replace("\\","/"); java.util.zip.ZipEntry ze = new java.util.zip.ZipEntry(f); ze.setMethod(java.util.zip.ZipEntry.DEFLATED); zos.putNextEntry(ze); //FileInputStreamの作成 java.io.FileInputStream fis = new java.io.FileInputStream(file); //書込み sbyte[] buffer = new sbyte[8192]; int len; while((len = fis.read(buffer, 0, buffer.Length)) > 0) { zos.write(buffer, 0, len); } //閉じる fis.close(); zos.closeEntry(); } zos.close(); fos.close(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ このようにjava.util.zip内のクラスを使うと簡単にZipの扱いができるようになりますが、現在のバージョン(.NET Framework 1.1)では、このやり方は非常に多くの問題があることが分かっています(2.0では修正されるようです)。例えば、上記の方法でパス名に日本語を含むファイルを圧縮するとZip書庫は正常に作成されません。また、ZipEntry.setTimeで日時を指定できません。さらに、先に紹介した「Using the Zip Classes in the J# Class Libraries to Compress Files and Data with C#」のサンプルでは、サイズの大きいバイナリファイルを圧縮すると、エラーが発生します(new ZipFileでエラーが発生しますが、上記のコードではこれを使用していません)。これらのバグについては、次のURL先が参考になります。 [URL]Bug when using the java.util.zip classes to write zip files http://www.codeproject.com/buglist/jslibzipbug.asp [URL]Zip and Unzip from a C# program using J# runtime http://codeproject.com/csharp/VmEasyZipUnZip.asp さらに別の方法として、Zipを扱う有名なライブラリである#ziplibを使う方法があります。(現在のバージョンは0.81。) [URL]#ziplib http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx #ziplibを使ってZipを扱うサンプルを以下に紹介します。まずはZip内のファイルを列挙するコードから。先ほどのjava.util.zipのサンプルと似ていますね。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '作成するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '読み込む Dim fs As New System.IO.FileStream( _ zipPath, System.IO.FileMode.Open, _ System.IO.FileAccess.Read, System.IO.FileShare.Read) Dim zis As New ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs) 'ZIP内のファイル情報を取得 Dim ze As ICSharpCode.SharpZipLib.Zip.ZipEntry While True ze = zis.GetNextEntry() If ze Is Nothing Then Exit While End If If Not ze.IsDirectory Then '情報を表示する Console.WriteLine("ファイル名 : {0}", ze.Name) Console.WriteLine("サイズ : {0} bytes", ze.Size) Console.WriteLine("圧縮サイズ : {0} bytes", _ ze.CompressedSize) Console.WriteLine("CRC : {0:X}", ze.Crc) Console.WriteLine("日時 : {0}", ze.DateTime) Console.WriteLine() End If End While '閉じる zis.Close() fs.Close() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //作成するZIPファイルの設定 string zipPath = "C:\\test.zip"; //読み込む System.IO.FileStream fs = new System.IO.FileStream( zipPath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); ICSharpCode.SharpZipLib.Zip.ZipInputStream zis = new ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs); //ZIP内のファイル情報を取得 ICSharpCode.SharpZipLib.Zip.ZipEntry ze; while ((ze = zis.GetNextEntry()) != null) { if (!ze.IsDirectory) { //情報を表示する Console.WriteLine("ファイル名 : {0}", ze.Name); Console.WriteLine("サイズ : {0} bytes", ze.Size); Console.WriteLine("圧縮サイズ : {0} bytes", ze.CompressedSize); Console.WriteLine("CRC : {0:X}", ze.Crc); Console.WriteLine("日時 : {0}", ze.DateTime); Console.WriteLine(); } } //閉じる zis.Close(); fs.Close(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 次はZip書庫内のすべてのファイルを展開するコードです。これもjava.util.zipのサンプルと似ています。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '展開するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '展開先のフォルダの設定 Dim extractDir As String = "C:\temp" '読み込む Dim fs As New System.IO.FileStream( _ zipPath, System.IO.FileMode.Open, _ System.IO.FileAccess.Read, System.IO.FileShare.Read) Dim zis As New ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs) 'ZIP内のファイル情報を取得 Dim ze As ICSharpCode.SharpZipLib.Zip.ZipEntry While True ze = zis.GetNextEntry() If ze Is Nothing Then Exit While End If If Not ze.IsDirectory Then 'ファイル名 Dim fileName As String = System.IO.Path.GetFileName(ze.Name) '展開先のフォルダ Dim destDir As String = System.IO.Path.Combine( _ extractDir, System.IO.Path.GetDirectoryName(ze.Name)) System.IO.Directory.CreateDirectory(destDir) '展開先のパス Dim destPath As String = _ System.IO.Path.Combine(destDir, fileName) '書込み Dim writer As New System.IO.FileStream( _ destPath, System.IO.FileMode.Create, _ System.IO.FileAccess.Write, System.IO.FileShare.Write) Dim buffer(2047) As Byte Dim len As Integer While True len = zis.Read(buffer, 0, buffer.Length) If len <= 0 Then Exit While End If writer.Write(buffer, 0, len) End While '閉じる writer.Close() End If End While zis.Close() fs.Close() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //展開するZIPファイルの設定 string zipPath = "C:\\test.zip"; //展開先のフォルダの設定 string extractDir = "C:\\temp"; //読み込む System.IO.FileStream fs = new System.IO.FileStream( zipPath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); ICSharpCode.SharpZipLib.Zip.ZipInputStream zis = new ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs); //ZIP内のファイル情報を取得 ICSharpCode.SharpZipLib.Zip.ZipEntry ze; while ((ze = zis.GetNextEntry()) != null) { if (!ze.IsDirectory) { //ファイル名 string fileName = System.IO.Path.GetFileName(ze.Name); //展開先のフォルダ string destDir = System.IO.Path.Combine(extractDir, System.IO.Path.GetDirectoryName(ze.Name)); System.IO.Directory.CreateDirectory(destDir); //展開先のパス string destPath = System.IO.Path.Combine(destDir, fileName); //書込み System.IO.FileStream writer = new System.IO.FileStream( destPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Write); byte[] buffer = new byte[2048]; int len; while ((len = zis.Read(buffer, 0, buffer.Length)) > 0) { writer.Write(buffer, 0, len); } //閉じる writer.Close(); } } zis.Close(); fs.Close(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 最後にファイルを圧縮してZip書庫を作成するサンプルです。ここではヘッダでエントリの情報を設定していますが、これを省略すると、フッタに書き込まれます。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '作成するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '圧縮するファイルの設定 Dim filePaths As String() = _ { _ "C:\1.txt", _ "D:\2.txt" _ } Dim crc As New ICSharpCode.SharpZipLib.Checksums.Crc32 Dim writer As New System.IO.FileStream( _ zipPath, System.IO.FileMode.Create, _ System.IO.FileAccess.Write, System.IO.FileShare.Write) Dim zos As New ICSharpCode.SharpZipLib.Zip.ZipOutputStream(writer) '圧縮レベルを設定する zos.SetLevel(6) 'Zipにファイルを追加する Dim file As String For Each file In filePaths 'ZIPに追加するときのファイル名を決定する Dim f As String = System.IO.Path.GetFileName(file) 'ディレクトリを保持する時は次のようにする 'Dim f As String = file.Remove( _ ' 0, System.IO.Path.GetPathRoot(file).Length) 'f = f.Replace("\", "/") Dim ze As New ICSharpCode.SharpZipLib.Zip.ZipEntry(f) 'ヘッダを設定する 'ファイルを読み込む Dim fs As New System.IO.FileStream( _ file, System.IO.FileMode.Open, _ System.IO.FileAccess.Read, System.IO.FileShare.Read) Dim buffer(fs.Length) As Byte fs.Read(buffer, 0, buffer.Length) fs.Close() 'CRCを設定する crc.Reset() crc.Update(buffer) ze.Crc = crc.Value 'サイズを設定する ze.Size = buffer.Length '時間を設定する ze.DateTime = DateTime.Now '新しいエントリの追加を開始 zos.PutNextEntry(ze) '書き込む zos.Write(buffer, 0, buffer.Length) Next file zos.Close() writer.Close() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //作成するZIPファイルの設定 string zipPath = "C:\\test.zip"; //圧縮するファイルの設定 string[] filePaths = { @"C:\test1.txt", @"D:\Download\mt.txt" }; ICSharpCode.SharpZipLib.Checksums.Crc32 crc = new ICSharpCode.SharpZipLib.Checksums.Crc32(); System.IO.FileStream writer = new System.IO.FileStream( zipPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Write); ICSharpCode.SharpZipLib.Zip.ZipOutputStream zos = new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(writer); //圧縮レベルを設定する zos.SetLevel(6); //Zipにファイルを追加する foreach (string file in filePaths) { //ZIPに追加するときのファイル名を決定する string f = System.IO.Path.GetFileName(file); //ディレクトリを保持する時は次のようにする //string f = file.Remove( // 0, System.IO.Path.GetPathRoot(file).Length); //f = f.Replace("\\","/"); ICSharpCode.SharpZipLib.Zip.ZipEntry ze = new ICSharpCode.SharpZipLib.Zip.ZipEntry(f); //ヘッダを設定する //ファイルを読み込む System.IO.FileStream fs = new System.IO.FileStream( file, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); byte[] buffer = new byte[fs.Length]; fs.Read(buffer, 0, buffer.Length); fs.Close(); //CRCを設定する crc.Reset(); crc.Update(buffer); ze.Crc = crc.Value; //サイズを設定する ze.Size = buffer.Length; //時間を設定する ze.DateTime = DateTime.Now; //新しいエントリの追加を開始 zos.PutNextEntry(ze); //書き込む zos.Write(buffer, 0, buffer.Length); } zos.Close(); writer.Close(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ これ以外の方法では、アンマネージDLLを使う方法があります。これに関しては、次のURL先をご覧ください。 [URL]遅延バインディングによりアンマネージDLL関数を呼び出す http://dobon.net/vb/dotnet/links/extractarchive.html ─────────────────────────────── ■.NET質問箱 ─────────────────────────────── 「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込 まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、 Q&A形式にまとめて紹介します。 [URL]どぼん!のプログラミング掲示板 http://dobon.net/vb/bbs.html ─────────────────────────────── ●マルチTIFFやアニメーションGIFに含まれるすべてのイメージを表示するには? 【質問】 マルチTIFFやアニメーションGIFのように複数のイメージを含んだ画像ファイルからすべてのイメージを取り出して表示したいのですが、どのようにすればよいですか? 【回答】 これには、Image.SelectActiveFrameメソッドでアクティブなフレームを変更し、すべてのフレームのイメージを表示するようにすればよいでしょう。 まず、複数のイメージを含んだ画像ファイルをImageオブジェクトに読み込みます。そして、Image.FrameDimensionsListプロパティにより、フレームのディメンションGUIDを取得し、これからFrameDimensionオブジェクトを作成します。これを使用して、SelectActiveFrameメソッドを呼び出します。 以下にアニメーションGIFファイル(C:\test.gif)内のすべてのイメージをPictureBox(PictureBox1)に表示するサンプルを示します。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '画像ファイルのパス Dim filePath As String = "C:\test.gif" Dim g As Graphics = PictureBox1.CreateGraphics() '画像を読み込む Dim img As Image = Image.FromFile(filePath) 'FrameDimensionを取得 Dim fd As New FrameDimension(img.FrameDimensionsList(0)) 'フレーム数を取得 Dim fd_count As Integer = img.GetFrameCount(fd) Dim y As Integer = 0 Dim i As Integer For i = 0 To fd_count - 1 'フレームを選択 img.SelectActiveFrame(fd, i) '画像を表示 g.DrawImage(img, 0, y, img.Width, img.Height) y += img.Height Next i img.Dispose() g.Dispose() ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //画像ファイルのパス string filePath = "C:\\test.gif"; Graphics g = PictureBox1.CreateGraphics(); //画像を読み込む Image img = Image.FromFile(filePath); //FrameDimensionを取得 FrameDimension fd = new FrameDimension(img.FrameDimensionsList[0]); //フレーム数を取得 int fd_count = img.GetFrameCount(fd); int y = 0; for (int i = 0; i < fd_count; i++) { //フレームを選択 img.SelectActiveFrame(fd, i); //画像を表示 g.DrawImage(img, 0, y, img.Width, img.Height); y += img.Height; } img.Dispose(); g.Dispose(); ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ○この記事の基になった掲示板のスレッド [題名] すべて印刷したい [投稿者(敬称略)] john, 管理人 [URL] http://dobon.net/vb/bbs/log3-4/2435.html ─────────────────────────────── ●TextBoxコントロールのEnabledプロパティをFalseにしても前景色と背景色を変えないようにするには? 【質問】 System.Windows.Forms.TextBoxコントロールのEnabledプロパティをFalseにすると、文字の色と背景が灰色になりますが、EnabledプロパティをFalseにしても文字の色と背景色が変わらないようにできませんか? 【回答】 TextBoxの背景色だけであれば、EnabledプロパティをFalseにした後、BackColorプロパティを設定するだけで、色を変更できます。ただし、ForeColorはこの方法では変更できないようです。(.NET Framework 1.1) ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ TextBox1.Enabled = False '背景色を灰色にしない TextBox1.BackColor = TextBox1.BackColor ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ TextBox1.Enabled = false; //背景色を灰色にしない TextBox1.BackColor = TextBox1.BackColor; ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ TextBoxの前景色を変えないようにするには、EnabledプロパティをFalseにする代わりに、ReadOnlyプロパティをTrueにするという方法があります。ReadOnlyプロパティをTrueにしても背景色は灰色となりますが、上の例と同様にBackColorプロパティを設定すれば、背景色を変えなくすることもできます。 ReadOnlyを使うのではなく、どうしてもEnabledプロパティをFalseにしても前景色と背景色が変わらないようにしたいということであれば、TextBoxクラスから派生したクラスを作成し、OnPaintメソッドをオーバーライドすることにより自分で文字列を描画するという方法があります。 この方法については、「Windows Forms FAQ」で紹介されています。 [URL]Windows Forms FAQ 27.15 When I set a TextBox to Readonly or set Enabled to false, the text color is gray. How can I force it to be the color specified in the ForeColor property of the TextBox. http://www.syncfusion.com/FAQ/WinForms/FAQ_c94c.asp#q866q しかし残念ながらここに紹介されている方法では、TextBoxのEnabledがTrueの時に別のフォント(システムフォント?)でTextが表示されてしまいます。 これを防ぐには、TextBoxのEnabledがFalseの時だけ自分で描画するようにします。次の例ではOnEnabledChangedメソッドをオーバーライドすることにより、EnabledがTrueの時のみ独自に描画するようにしています。このクラスはTextAlignやRightToLeftなどのプロパティを一切無視していますので、あくまで参考としてご覧ください。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ''' ''' EnabledがFalseでも前景色、背景色が変わらないTextBox ''' Class MyTextBox Inherits TextBox Protected Overrides Sub OnEnabledChanged(ByVal e As EventArgs) MyBase.OnEnabledChanged(e) 'EnabledがFalseの時だけ自分で描画する If Me.Enabled Then Me.SetStyle(ControlStyles.UserPaint, False) Else Me.SetStyle(ControlStyles.UserPaint, True) End If '再描画 Me.Invalidate() End Sub 'TextBoxを描画する Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) MyBase.OnPaint(e) Dim b As New System.Drawing.SolidBrush(Me.ForeColor) '文字列を描画する e.Graphics.DrawString(Me.Text, Me.Font, b, -1, 1) b.Dispose() End Sub End Class ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ /// /// EnabledがFalseでも前景色、背景色が変わらないTextBox /// class MyTextBox : TextBox { protected override void OnEnabledChanged(EventArgs e) { base.OnEnabledChanged(e); //EnabledがFalseの時だけ自分で描画する if (this.Enabled) this.SetStyle(ControlStyles.UserPaint, false); else this.SetStyle(ControlStyles.UserPaint, true); //再描画 this.Invalidate(); } //TextBoxを描画する protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); System.Drawing.Brush b = new System.Drawing.SolidBrush(this.ForeColor); //文字列を描画する e.Graphics.DrawString(this.Text, this.Font, b, -1, 1); b.Dispose(); } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ このような方法を無理して使うよりも、できることならReadOnlyプロパティを使うか、別の持った簡単な方法を考える方がよいと思います(下記URL参照)。 ○この記事の基になった掲示板のスレッド [題名] Enabled=FALSEの時の文字色 [投稿者(敬称略)] あびこ, 琴, 管理人 [URL] http://dobon.net/vb/bbs/log3-4/2439.html [題名] テキストボックスコントロール の ENABLED が FALSE の時に、表示しているテキストの色を変更する方法 [投稿者(敬称略)] ぽろ, 通りすがりのVBラー, Tom's [URL] http://dobon.net/vb/bbs/log3-5/2796.html [題名] コントロールをロックしたい。 [投稿者(敬称略)] あり, よねKEN, ant, java.lang.Nullpo [URL] http://dobon.net/vb/bbs/log3-12/6734.html [題名] パネル上のコントロール制御 [投稿者(敬称略)] えびせん, ピラルク [URL] http://dobon.net/vb/bbs/log3-1/566.html [題名] GroupBoxの扱いについて [投稿者(敬称略)] nao, ぺがらぼ [URL] http://dobon.net/vb/bbs/log3-8/4754.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 - 2004 DOBON! All rights reserved. ===============================