• 追加された行はこの色です。
  • 削除された行はこの色です。
#title(.NETプログラミング研究 第49号)

#navi(.NETプログラミング研究)

#contents

*.NETプログラミング研究 第49号 [#rf0559ee]

明けましておめでとうございます。今年も「.NETプログラミング研究」をよろしくお願いいたします。

**ピンポイントリンク [#w9bac4cc]

***ZIP書庫の作成、閲覧、展開を行う [#a079787e]

#column(注意){{
この記事の最新版は「[[J#のライブラリを使ってZIP圧縮、展開(解凍)、リスト表示を行う>http://dobon.net/vb/dotnet/links/createzipfile.html]]」で公開しています。
この記事の最新版は「[[J#のライブラリを使ってZIP圧縮、展開(解凍)、リスト表示を行う>https://dobon.net/vb/dotnet/links/createzipfile.html]]」で公開しています。
}}

ここでは、C#またはVB.NETでZip書庫を扱う(作成、閲覧、展開)方法を紹介します。

C#、VB.NETには標準ではZipを扱う方法が用意されていませんが、J#にはvjslib.dllというものがあり、この中のjava.util.zip名前空間にあるクラスを使うことにより、Zipを扱うことが出来ます。

この方法は、次の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書庫内のファイル(エントリ)の情報を列挙するコードです。

#code(vbnet){{
'作成する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()
}}

#code(csharp){{
//作成する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();
}}

次はZip書庫内のファイルを展開するコードです。ここでは書庫内のすべてのファイルを展開しています。

#code(vbnet){{
'展開する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()
}}

#code(csharp){{
//展開する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();
}}

最後は指定したファイルを圧縮してZip書庫を作成するコードです。

#code(vbnet){{
'作成する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()
}}

#code(csharp){{
//作成する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();
}}

このように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先が参考になります。

-[[Bug when using the java.util.zip classes to write zip files>http://www.codeproject.com/buglist/jslibzipbug.asp]]
-[[Zip and Unzip from a C# program using J# runtime>http://codeproject.com/csharp/VmEasyZipUnZip.asp]]

さらに別の方法として、Zipを扱う有名なライブラリである#ziplibを使う方法があります。(現在のバージョンは0.81。)

-[[#ziplib>http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx]]

#ziplibを使ってZipを扱うサンプルを以下に紹介します。まずはZip内のファイルを列挙するコードから。先ほどのjava.util.zipのサンプルと似ていますね。

#code(vbnet){{
'作成する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()
}}

#code(csharp){{
//作成する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();
}}

次はZip書庫内のすべてのファイルを展開するコードです。これもjava.util.zipのサンプルと似ています。

#code(vbnet){{
'展開する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()
}}

#code(csharp){{
//展開する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();
}}

最後にファイルを圧縮してZip書庫を作成するサンプルです。ここではヘッダでエントリの情報を設定していますが、これを省略すると、フッタに書き込まれます。

#code(vbnet){{
'作成する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()
}}

#code(csharp){{
//作成する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();
}}

これ以外の方法では、アンマネージDLLを使う方法があります。これに関しては、次のURL先をご覧ください。

-[[遅延バインディングによりアンマネージDLL関数を呼び出す>http://dobon.net/vb/dotnet/links/extractarchive.html]]
-[[遅延バインディングによりアンマネージDLL関数を呼び出す>https://dobon.net/vb/dotnet/links/extractarchive.html]]

**.NET質問箱 [#ode20d02]

「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、Q&A形式にまとめて紹介します。

-[[どぼん!のプログラミング掲示板>http://dobon.net/vb/bbs.html]]
-[[どぼん!のプログラミング掲示板>https://dobon.net/vb/bbs.html]]

***マルチTIFFやアニメーションGIFに含まれるすべてのイメージを表示するには? [#sf25b7e9]

#column(注意){{
この記事の最新版は「[[マルチTIFFやアニメーションGIFに含まれるすべてのイメージを表示する>http://dobon.net/vb/dotnet/graphics/selectactiveframe.html]]」で公開しています。
この記事の最新版は「[[マルチTIFFやアニメーションGIFに含まれるすべてのイメージを表示する>https://dobon.net/vb/dotnet/graphics/selectactiveframe.html]]」で公開しています。
}}

''【質問】''

マルチTIFFやアニメーションGIFのように複数のイメージを含んだ画像ファイルからすべてのイメージを取り出して表示したいのですが、どのようにすればよいですか?

''【回答】''

これには、Image.SelectActiveFrameメソッドでアクティブなフレームを変更し、すべてのフレームのイメージを表示するようにすればよいでしょう。

まず、複数のイメージを含んだ画像ファイルをImageオブジェクトに読み込みます。そして、Image.FrameDimensionsListプロパティにより、フレームのディメンションGUIDを取得し、これからFrameDimensionオブジェクトを作成します。これを使用して、SelectActiveFrameメソッドを呼び出します。

以下にアニメーションGIFファイル(C:\test.gif)内のすべてのイメージをPictureBox(PictureBox1)に表示するサンプルを示します。

#code(vbnet){{
'画像ファイルのパス
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()
}}

#code(csharp){{
//画像ファイルのパス
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();
}}

○この記事の基になった掲示板のスレッド

-[[すべて印刷したい | 投稿者(敬称略) john, 管理人>http://dobon.net/vb/bbs/log3-4/2435.html]]
-[[すべて印刷したい | 投稿者(敬称略) john, 管理人>https://dobon.net/vb/bbs/log3-4/2435.html]]

***TextBoxコントロールのEnabledプロパティをFalseにしても前景色と背景色を変えないようにするには? [#q9d06263]

#column(注意){{
この記事の最新版は「[[TextBoxコントロールのEnabledプロパティをFalseにしても前景色と背景色を変えないようにする>http://dobon.net/vb/dotnet/control/tbenabledfalse.html]]」で公開しています。
この記事の最新版は「[[TextBoxコントロールのEnabledプロパティをFalseにしても前景色と背景色を変えないようにする>https://dobon.net/vb/dotnet/control/tbenabledfalse.html]]」で公開しています。
}}

''【質問】''

System.Windows.Forms.TextBoxコントロールのEnabledプロパティをFalseにすると、文字の色と背景が灰色になりますが、EnabledプロパティをFalseにしても文字の色と背景色が変わらないようにできませんか?

''【回答】''

TextBoxの背景色だけであれば、EnabledプロパティをFalseにした後、BackColorプロパティを設定するだけで、色を変更できます。ただし、ForeColorはこの方法では変更できないようです。(.NET Framework 1.1)

#code(vbnet){{
TextBox1.Enabled = False
'背景色を灰色にしない
TextBox1.BackColor = TextBox1.BackColor
}}

#code(csharp){{
TextBox1.Enabled = false;
//背景色を灰色にしない
TextBox1.BackColor = TextBox1.BackColor;
}}

TextBoxの前景色を変えないようにするには、EnabledプロパティをFalseにする代わりに、ReadOnlyプロパティをTrueにするという方法があります。ReadOnlyプロパティをTrueにしても背景色は灰色となりますが、上の例と同様にBackColorプロパティを設定すれば、背景色を変えなくすることもできます。

ReadOnlyを使うのではなく、どうしてもEnabledプロパティをFalseにしても前景色と背景色が変わらないようにしたいということであれば、TextBoxクラスから派生したクラスを作成し、OnPaintメソッドをオーバーライドすることにより自分で文字列を描画するという方法があります。

この方法については、「Windows Forms FAQ」で紹介されています。

-[[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などのプロパティを一切無視していますので、あくまで参考としてご覧ください。

#code(vbnet){{
''' <summary>
''' EnabledがFalseでも前景色、背景色が変わらないTextBox
''' </summary>
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
}}

#code(csharp){{
/// <summary>
/// EnabledがFalseでも前景色、背景色が変わらないTextBox
/// </summary>
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();
    }
}
}}

このような方法を無理して使うよりも、できることならReadOnlyプロパティを使うか、別の持った簡単な方法を考える方がよいと思います(下記URL参照)。

○この記事の基になった掲示板のスレッド

-[[Enabled=FALSEの時の文字色 | 投稿者(敬称略) あびこ, 琴, 管理人>http://dobon.net/vb/bbs/log3-4/2439.html]]
-[[テキストボックスコントロール の ENABLED が FALSE の時に、表示しているテキストの色を変更する方法 | 投稿者(敬称略) ぽろ, 通りすがりのVBラー, Tom's>http://dobon.net/vb/bbs/log3-5/2796.html]]
-[[コントロールをロックしたい。 | 投稿者(敬称略) あり, よねKEN, ant, java.lang.Nullpo>http://dobon.net/vb/bbs/log3-12/6734.html]]
-[[パネル上のコントロール制御 | 投稿者(敬称略) えびせん, ピラルク>http://dobon.net/vb/bbs/log3-1/566.html]]
-[[GroupBoxの扱いについて | 投稿者(敬称略) nao, ぺがらぼ>http://dobon.net/vb/bbs/log3-8/4754.html]]
-[[Enabled=FALSEの時の文字色 | 投稿者(敬称略) あびこ, 琴, 管理人>https://dobon.net/vb/bbs/log3-4/2439.html]]
-[[テキストボックスコントロール の ENABLED が FALSE の時に、表示しているテキストの色を変更する方法 | 投稿者(敬称略) ぽろ, 通りすがりのVBラー, Tom's>https://dobon.net/vb/bbs/log3-5/2796.html]]
-[[コントロールをロックしたい。 | 投稿者(敬称略) あり, よねKEN, ant, java.lang.Nullpo>https://dobon.net/vb/bbs/log3-12/6734.html]]
-[[パネル上のコントロール制御 | 投稿者(敬称略) えびせん, ピラルク>https://dobon.net/vb/bbs/log3-1/566.html]]
-[[GroupBoxの扱いについて | 投稿者(敬称略) nao, ぺがらぼ>https://dobon.net/vb/bbs/log3-8/4754.html]]

**コメント [#j0c39578]
#comment

//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2005-01-11 (火) 06:00:00,DOBON!,2010-03-22 (月) 01:48:01,DOBON!)


[ トップ ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]