.NETプログラミング研究 第38号

.NET質問箱

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

Microsoft Officeでコピーした図をPictureBoxに表示するには?

注意

この記事の最新版は「Microsoft Officeでコピーした図をPictureBoxに表示する」で公開しています。

【質問】

Microsoft Office Wordなどで作成した図をクリップボードにコピーした時、このデータを取得してPictureBoxに表示するために次のようなコードを書いたのですがうまくいきません。どのようにすればできますか?

  1
  2
  3
  4
  5
  6
  7
Dim data As IDataObject = Clipboard.GetDataObject()
'クリップボードにあるデータが拡張メタファイル形式か調べる
If data.GetDataPresent(DataFormats.EnhancedMetafile) Then
    '拡張メタファイル形式でデータを取得する
    PictureBox1.Image = _
        CType(data.GetData(DataFormats.EnhancedMetafile), Image)
End If
  1
  2
  3
  4
  5
  6
  7
  8
IDataObject data = Clipboard.GetDataObject();
//クリップボードにあるデータが拡張メタファイル形式か調べる
if (data.GetDataPresent(DataFormats.EnhancedMetafile))
{
    //拡張メタファイル形式でデータを取得する
    PictureBox1.Image =
        (Image) data.GetData(DataFormats.EnhancedMetafile);
}

【回答】

この問題の解決法は、DOBON.NET掲示板へのピラルクさんの投稿や、ニュースグループでのマイクロソフトのLion Shiさんの投稿が参考になります。

Lion Shiさんの投稿によると、Microsoft Officeの図をクリップボードにコピーした時、そのデータは上記のコードのようにEnhancedMetafile形式では取得できないということです。

クリップボードにコピーされたデータは、EnhancedMetafile形式の他に、Office Drawing Shape Format、MetaFilePict、PNG+Office Art、JFIF+Office Art、GIF+Office Art、PNG、JFIF、GIF、ActiveClipboard、HTML Format形式に関連付けられており、このうち、HTML Format以外はMemoryStreamオブジェクトとしてデータを取得できます。

つまり、Microsoft Officeでコピーした図を、例えばPNG形式でデータを取得する場合は、次のようになります。ここではフォームにピクチャボックス"PictureBox1"があり、このPictureBox1にクリップボードにある図を表示するものとします。

  1
  2
  3
  4
  5
  6
  7
  8
Dim data As IDataObject = Clipboard.GetDataObject()
'クリップボードにあるデータがPNG形式か調べる
If data.GetDataPresent("PNG") Then
    'PNG形式でデータをMemoryStreamとして取得する
    Dim ms As MemoryStream = CType(data.GetData("PNG"), MemoryStream)
    'Imageオブジェクトに変換する
    PictureBox1.Image = Image.FromStream(ms)
End If
  1
  2
  3
  4
  5
  6
  7
  8
  9
IDataObject data = Clipboard.GetDataObject();
//クリップボードにあるデータがPNG形式か調べる
if (data.GetDataPresent("PNG"))
{
    //PNG形式でデータをMemoryStreamとして取得する
    MemoryStream ms = (MemoryStream) data.GetData("PNG");
    //Imageオブジェクトに変換する
    PictureBox1.Image = Image.FromStream(ms);
}

"PNG"以外の形式を試してみたところ、上記のコードで"PNG"の部分を以下の文字列に変更した場合にのみ成功するようです。

"PNG+Office Art"
"JFIF+Office Art"
"GIF+Office Art"
"JFIF"
"GIF"

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

用紙のサイズをコンボボックスに表示して、選択して印刷する

注意

この記事の最新版は「用紙のサイズをコンボボックスに表示して、選択して印刷する」で公開しています。

【質問】

PrintDocumentクラスを使って印刷する際に、プリンタで印刷可能な用紙のサイズをコンボボックスに一覧表示して、選択された用紙サイズで印刷されるようにしたいのですが、どのようにすればよいのでしょうか?

【回答】

プリンタでサポートされている用紙サイズは、PrintDocumentオブジェクトのPrinterSettings.PaperSizesプロパティで取得できます。

フォームにPrintDocumentオブジェクト"PrintDocument1"とコンボボックス"ComboBox1"がすでに配置されている時、PrintDocument1で指定されているプリンタでサポートされている用紙サイズをComboBox1に表示するには、次のようにします。ComboBox1にはPaperSizeオブジェクトを追加し、ComboBox1のDisplayMemberプロパティを"PaperName"とすることにより、ComboBox1にはPaperSizeのPaperNameプロパティで取得できる文字列が表示されるようにしています。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
'ComboBox1の項目をクリアする
ComboBox1.Items.Clear()
 
'表示するプロパティをPaperNameとする
ComboBox1.DisplayMember = "PaperName"
 
'PaperSizeをComboBox1に追加していく
Dim ps As System.Drawing.Printing.PaperSize
For Each ps In PrintDocument1.PrinterSettings.PaperSizes
    ComboBox1.Items.Add(ps)
Next ps
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
//ComboBox1の項目をクリアする
ComboBox1.Items.Clear();
 
//表示するプロパティをPaperNameとする
ComboBox1.DisplayMember = "PaperName";
 
//PaperSizeをComboBox1に追加していく
foreach (System.Drawing.Printing.PaperSize ps
                in PrintDocument1.PrinterSettings.PaperSizes)
{
    ComboBox1.Items.Add(ps);
}

ComboBox1で選択された用紙サイズで印刷するには、次のようにします。単に、DefaultPageSettings.PaperSizeプロパティをComboBox1.SelectedItemに変更しているだけです。(PrintDocument1のPrintPageイベントハンドラは省略されています。PrintPageイベントハンドラがないと、印刷はできません。印刷する方法に関しては、DOBON.NETの「印刷する」などをご覧ください。)

  1
  2
  3
  4
  5
  6
'用紙サイズをComboBox1で選択されているサイズにする
PrintDocument1.DefaultPageSettings.PaperSize = _
    CType(ComboBox1.SelectedItem, System.Drawing.Printing.PaperSize)
 
'印刷する
PrintDocument1.Print()
  1
  2
  3
  4
  5
  6
//用紙サイズをComboBox1で選択されているサイズにする
PrintDocument1.DefaultPageSettings.PaperSize =
    (System.Drawing.Printing.PaperSize) ComboBox1.SelectedItem;
 
//印刷する
PrintDocument1.Print();

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

FileSystemWatcherでファイル名が小文字になる

注意

この記事の最新版は「FileSystemWatcherでファイル名が小文字になる問題の解決法」で公開しています。

【質問】

ファイルの変更を監視するためにFileSystemWatcherクラスを使っていますが、Changedイベントハンドラで取得できるFileSystemEventArgsオブジェクトのFullPathやNameプロパティのファイル名が小文字になってしまいます。正しいファイル名を取得するにはどのようにすればよいのでしょうか?

【回答】

これは.NET Frameworkのバグのようです(.NET Framework 1.1でも修正されていないようです)。よってこの問題を解決するには、今のところ小文字のファイル名から正しいファイル名を取得する何らかの方法を考えるしかないようです。

このような小文字のファイル名から正しいファイル名を取得するための方法が、ニュースグループで紹介されていました。

この記事によると、ルートフォルダから順番にDirectoryInfoクラスのGetFileSystemInfosプロパティを使って一つずつ正しいフォルダ名(最後はファイル名)を取得していくという方法でうまくいくとのことです。

上に紹介した記事にコードもありますが、私なりに書いたものを以下に紹介します。このコード(メソッド)は、短いファイル名から長いファイル名を取得するためにも使えるため、"GetLongPath"という名前をつけています。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
''' <summary>
''' 短いファイル名から長いファイル名を取得する
''' </summary>
''' <param name="path">短いファイル名(フルパス)</param>
''' <returns>長いファイル名</returns>
Public Shared Function GetLongPath(ByVal path As String) As String
    'ルートディレクトリを取得
    Dim root As String = System.IO.Path.GetPathRoot(path)
    'ルートディレクトリ以降を'\'で分割
    Dim folders As String() = path.Substring(root.Length). _
        Split(System.IO.Path.DirectorySeparatorChar)
 
    Dim res As String = root
    Dim name As String
    For Each name In folders
        Dim di = New DirectoryInfo(res)
        'ディレクトリ(またはファイル)を探す
        Dim fsi As System.IO.FileSystemInfo() = _
            di.GetFileSystemInfos(name)
        If fsi.Length = 1 Then
            res = fsi(0).FullName
        Else
            Throw New Exception("ERROR")
        End If
    Next name
 
    Return res
End Function
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
/// <summary>
/// 短いファイル名から長いファイル名を取得する
/// </summary>
/// <param name="path">短いファイル名(フルパス)</param>
/// <returns>長いファイル名</returns>
public static string GetLongPath(string path)
{
    //ルートディレクトリを取得
    string root = System.IO.Path.GetPathRoot(path);
    //ルートディレクトリ以降を'\'で分割
    string[] folders = path.Substring(root.Length)
        .Split(System.IO.Path.DirectorySeparatorChar);
 
    string res = root;
    foreach (string name in folders)
    {
        System.IO.DirectoryInfo di = new DirectoryInfo(res);
        //ディレクトリ(またはファイル)を探す
        System.IO.FileSystemInfo[] fsi = di.GetFileSystemInfos(name);
        if (fsi.Length == 1)
            res = fsi[0].FullName;
        else
            throw new Exception("ERROR");
    }
 
    return res;
}

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

コンピュータ雑学

ここでは、話すと人に嫌われるなまぬるいコンピュータに関する雑学を紹介します。

BASICの歴史とMicrosoftの誕生

BASIC(Beginner's All-purpose Symbolic Instruction Code)は初心者でも使いやすいプログラミング言語として、FORTRAN IIとALGOL 60を基礎に、1964年アメリカのDartmouth大学で数学者のJohn KemenyとThomas Kurtzによって開発されました(5月1日午前4時に初めてBASICプログラムが実行されたとされています)。

1974年、Popular Electronics誌で、世界初のパーソナルコンピュータ、MITS(Micro Instrumentation and Telemetry Systems)社のAltair 8080が紹介されると、これを見たPaul AllenとBill Gatesが、1975年、世界初のマイクロコンピュータ用言語である、Altair 8800用BASICインタープリタを開発しました。これをきっかけに、BASICがプログラミング言語として広まることになります。

Harvard大学の学生であったBill GatesとHoneywellの社員だったPaul Allenは、Paul AllenがHarvard大学にあったPDP-10を使ってAltairのエミュレータを作り、Bill GatesがBASICのコードを書きました。彼らは開発に8週間を費やしたといわれていますが、Bill Gatesはこの時書き上げたプログラムこそ人生で最高のプログラムだと語っているそうです。

Bill GatesとPaul Allenは1975年7月11日にMITS社とBASICのライセンス契約を結びました。同月、Bill Gatesが$910、Paul Allenが$606を出資し、Micro-Softを設立しました(その後、Microsoftとなります)。つまりMicrosoftの最初の商品はBASICだったわけで、これが今のVisual Basic .NETに引き継がれているのです。

コメント



ページ情報
  • カテゴリ : .NET
  • 作成日 : 2004-07-27 (火) 06:00:00
  • 作成者 : DOBON!
  • 最終編集日 : 2010-03-21 (日) 02:36:25
  • 最終編集者 : DOBON!
[ トップ ]   [ 編集 | 凍結 | 差分 | バックアップ | 添付 | 複製 | 名前変更 | リロード ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]