エクセルの画像データーを表示するには

解決


YOKO  2003-08-14 02:19:37  No: 108111  IP: [192.*.*.*]

はじめて質問いたします。
VB6でエクセルの画像データーを表示したいと思っています。
エクセル項目(イメージ:ファイル名)→ Data1→ Texit4→ Picture1 の流れでコマンドボタンをクリックすると、Picture1に画像が表示されるようにしたいのですが、次のページに移動したときに、表示する画像が有れば問題なく表示されます。画像がない場合には「パスが見つかりません」と出て終了しないといけなくなってしまいます。  If文で画像が有るときだけ表示するようにしたいのですが
式が分からなくて困っています。下記の式を使用しています。よろしくお願いします。

Private Sub Command2_Click()
 Picture1.Picture = LoadPicture(App.Path + "\" + Text4.Text)  ・・・デバッグすると黄色に
 Picture1.Visible = True
End Sub

'次のデータに移動したとき前回のデータを初期化します
Private Sub Data1_Validate(Action As Integer, Save As Integer)
   Text2.Visible = False
   MMControl1.FileName = ""
   Picture1.Picture = LoadPicture("")
End Sub

編集 削除
魔界の仮面弁士  2003-08-14 09:55:51  No: 108112  IP: [192.*.*.*]

『エクセルの画像データー』というのが、何の事を示しているのか
今ひとつ分からなかったのですが、とりあえず、
> If文で画像が有るときだけ表示するようにしたいのですが
について回答しておきます。

まず、ファイルの存在チェックは、Dir関数で行えます。
例えば、『Dir("C:\Test.bmp")』を実行して、それが
空の文字列を返せば、ファイルが無い、という意味になります。
(隠しファイル等の存在判定もしたい時は、Dir関数の第2引数も指定します)

ただし、これで判定できるのは、あくまでファイルの存在チェックだけです。
例えば、画像データが壊れていたり、あるいは、画像形式ではないファイルが
指定されていたりすれば、LoadPictureは失敗する事になるでしょう。
ですから、こういうときは『On Errorステートメント』を使って、
例外処理(エラートラップ処理)を行うのが一般的です。
(エラー処理の手順はヘルプに書かれていますので、そちらを参照して下さい)


それから、
  Picture1.Picture = LoadPicture(〜〜〜)
このような書き方は、本来は正しくありません。
これは旧バージョンとの互換性のために残された書き方であり、VB6では、
  Set Picture1.Picture = LoadPicture(〜〜〜)
のように、「Set ステートメント」を使うのが正しいのです。
(たまにヘルプ等でも、Setを使わない古い記述が使われていますけれどね)

VBの標準コントロールでは、互換性維持の理由から、Setを使わずとも
Pictureオブジェクトを指定できるようになっていますが、その他の
ActiveXコントロールなどでは、Setを使わないとエラーになってしまうものも
ありますので、オブジェクトの指定時には、必ず、Setを使うようにしてください。


最後にもう一つ。
App.Pathは、アプリがドライブのルートにある時には、
最後に "\" が付加された状態( C:\ など)で返されます。
できれば、
  Dim Path As String
  Path = App.Path
  If Right(Path, 1) = "\" Then
      Path = Path & Text1.Text
  Else
      Path = Path & "\" & Text1.Text
  End If
などのように、場合わけを行った方が良いと思います。

なお、FileSystemObjectオブジェクトには、この為に使える
「BuildPath メソッド」という物が用意されており、これを使うと
   Path = objFSO.BuildPath(App.Path, Text1.Text) 
このフォルダの区切(\)の付加処理が、正しく行われます。

編集 削除
YOKO  2003-08-14 16:56:53  No: 108113  IP: [192.*.*.*]

魔界の仮面弁士様  早速ご教授頂きましてありがとうございました。
画像データーは単純に「鳥」の行には「鳥の写真」というものです。画像が存在しないときも想定したときの動作がうまくいかなかったのですが、ご指摘頂いたように修正しましたところ、エラーもなく希望した通りに動作しました(画像形式以外のファイルも入れてみました)。
下記の式になりました。ありがとうございました。

'画像の表示
Private Sub Command2_Click()
 Dim Path As String    '以下絶対パス取得コード
  Path = App.Path
  If Right(Path, 1) = "\" Then
      Path = Path & Text4.Text
  Else
      Path = Path & "\" & Text4.Text
  End If
 Dir ("Text4.Text")        'ファイルの存在チェック
   If Text4.Text <> "" Then
    On Error Resume Next  'エラー処理
    
    Set Picture1.Picture = LoadPicture(App.Path + "\" + Text4.Text)
    Picture1.Visible = True
   End If
End Sub

編集 削除
魔界の仮面弁士  2003-08-15 09:53:14  No: 108114  IP: [192.*.*.*]

> Dir ("Text4.Text")        'ファイルの存在チェック
このコードでは、
  「カレントフォルダにある、"Text4.Text"という名前のファイル」
を調べている事になりますよ。ダブルコーテーションは外しましょう。

また、戻り値を受け取っていないようですが、これでは、
チェックになっていませんよ。(^_^;)
処理としては、
   Dim S As String
   S = Dir(Text4.Text)
   If S = "" Then
       'ファイルが見つからなかったとき
   Else
       'ファイルが見つかった時
   End If
のような感じになりますね。


それから、
>     Path = Path & "\" & Text4.Text
のように、「&演算子」で連結しているコードと
>     Set Picture1.Picture = LoadPicture(App.Path + "\" + Text4.Text)
のように、「+演算子」で連結しているコードが混在していますが、
混乱を避ける意味で、これらは「&演算子」に統一しておく事をお奨めします。

編集 削除
YOKO  2003-08-16 16:43:11  No: 108115  IP: [192.*.*.*]

魔界の仮面弁士様  引き続き野ご指摘ありがとうございます。色医尾rためしてみました結果、
Set Picture1.Picture = LoadPicture(App.Path + "\" + Text4.Text)のコードの括弧内は  Path でも  S  でもいいことが理解できました。
Else以下を無視させるために
If Text4.Text <> "" Then
    On Error Resume Next  'エラー処理
のコードを使用したのですが、一見正しく動作しているように見えてもこれではだめなんですね。
お教え頂いたコードに書き直して色々試してみました。
>Dim S As String
>  S = Dir(Text4.Text)
> If S = "" Then
>    'ファイルが見つからなかったとき
> Else
>       'ファイルが見つかった時
> End If
「ファイルが見つからなかったとき」にエラー処理の仕方が理解できなくて、「画像無し」の画像を表示させるようにしてみました。ところが、「ファイルが見つかった時」の行の  Set Picture1.Picture = LoadPicture(S)  をさして「ファイルが見つかりません」とエラーがでます。
 On Error Resume Next  以外を使用するのだと思うのですが何をどうしたらよいか分かりません。よろしくお願いします。

編集 削除
魔界の仮面弁士  2003-08-16 21:50:29  No: 108116  IP: [192.*.*.*]

> Set Picture1.Picture = LoadPicture(App.Path + "\" + Text4.Text)のコードの括弧内は  Path でも  S  でもいいことが理解できました。

基本的には、単なる「ファイル名」ではなく、ドライブ名から始まる
「フルパス」を指定するようにしてください。
つまり、"隅田川.bmp" のような文字列ではなく、"C:\Windows\隅田川.bmp" のような
文字列を指定する…という事です。
ファイル名だけの指定でも判定はできますが、この場合、CurDir関数が
どのディレクトリ名を返してくるかによって、結果が変わってしまいますので、
常に、「フルパス」形式にしておいた方が無難です。

> 「ファイルが見つからなかったとき」にエラー処理の仕方が理解できなくて
例えば、MsgBox関数を使って「ファイルが無いよ」と表示させて、さらに
  Set Picture1.Picture = LoadPicture()
などとして、「何も画像を表示させない」ようにしてみるとか。

> 「画像無し」の画像を表示させるようにしてみました。
なるほど。『「画像無し」の画像を表示させる』事まではできたのですね。

> Set Picture1.Picture = LoadPicture(S)  をさして「ファイルが見つかりません」とエラーがでます。
文字通りの意味でしょう。変数 S に、どのような文字列が格納されているかを
確認してみてください。おそらく、実在しないファイル名が指定されているのだと思います。

編集 削除
YOKO  2003-08-17 16:02:11  No: 108117  IP: [192.*.*.*]

魔界の仮面弁士様  VBを始めてまだ1ヶ月にならない未熟者にお付き合いいただきまして有難うございます。テキストにファイルが存在しない時にメッセージボックスを出して「画像なし」の画像を表示することができました。
画像形式以外のファイル(.wav .txt)が存在した時に「実行時エラー 481  ピクチャーが不正です」と出ます。これをファイルが存在しない時と同じように処理したいのですが方法が分かりません。
以下画像の表示コード
Private Sub Command2_Click()
 Dim Path As String    '以下絶対パス取得コード
  Path = App.Path
  If Right(Path, 1) = "\" Then
      Path = Path & Text4.Text
  Else
      Path = Path & "\" & Text4.Text
  End If
        
  Dim S As String
  S = Text4.Text
  If S = "" Then     'ファイルの存在チェック
     On Error Resume Next  'エラー処理
     'エラーが起こるかも知れない処理
     On Error GoTo 0
      If Err.Number = 0 Then
    'エラー時の処理
      MsgBox "エラーが発生しました。-" & Str(Err.Number) & ":" + Err.Description
      Err.Clear
      End If
      Set Picture1.Picture = LoadPicture(App.Path & "\non.jpg")
      Picture1.Visible = True
   Else
    
      Set Picture1.Picture = LoadPicture(App.Path & "\" & Text4.Text)
      Picture1.Visible = True
   End If
End Sub

Else〜 End Ifの間で処理すればいいと思うのですが、存在しない時と同じようにすると構文が変になってしまいうまくいきません。よろしくお願いします。

編集 削除
YOKO  2003-08-17 20:31:58  No: 108118  IP: [192.*.*.*]

魔界の仮面弁士様  On Error GoTo Err_Hendle を使用して、ファイルが存在しない時、ファイル形式が違う時  のどちらでも「画像がありません」の MsgBoxで  Okを押すと「画像がありません」の画像を出すことができました。 MsgBoxを出さなくしてみたり、「画像がありません」の画像を出さなくしてみたり、On Error GoTo Err_Hendle の記述行を変えてみたり色々試してみました。とりあえず下記のコードで落ち着きましたが正しいのかどうか不安です。御検証お願いします。
'画像の表示コード
Private Sub Command2_Click()
 Dim Path As String    '以下絶対パス取得コード
 Path = App.Path
  If Right(Path, 1) = "\" Then
      Path = Path & Text4.Text
  Else
      Path = Path & "\" & Text4.Text
  End If
        
  Dim S As String
  S = Text4.Text
  On Error GoTo Err_Hendle    '以降、エラーが出たらErr_Hendle:以下の処理
  
  If S = "" Then     'ファイルの存在チェック
     
  Else
    Set Picture1.Picture = LoadPicture(App.Path & "\" & Text4.Text)
    Picture1.Visible = True
    Exit Sub    'エラーが出なければプロシージャを抜ける
 End If

Err_Hendle:
     MsgBox "画像がありません"
     Set Picture1.Picture = LoadPicture(App.Path & "\non.jpg")
     Picture1.Visible = True

End Sub

編集 削除
魔界の仮面弁士  2003-08-18 03:44:11  No: 108119  IP: [192.*.*.*]

もしかして、どの時点で、どの変数に、どのような値が格納されているかを
明確に理解しておられないのではないでしょうか?
失礼ながら、どうも、いきあたりばったりで書いているように見受けられたので…。

とりあえず、コードの説明の前に、デバッグの手順を示しておきますね。
(既にデバッグの手法をご存知であれば、この部分は読み飛ばしてください)

まず、Clickイベントの先頭にカーソルを置いて、そこで「F9」キーを押してください。
(通常の設定であれば、これで茶色の反転表示になると思います)
これで、その行に『ブレークポイントが張られた』状態になります。

この状態で実行すると、ブレークポイントの位置で処理が一時中断します。
そこから、「F8」キーを押すと、キーを押すごとに、1行ずつ処理を
進ませていく事ができます。(ステップ実行)
このようにすると、どの行が実行されているのかが、明確になると思います。

このとき、変数名などの上にマウスカーソルを重ねると、その変数の
内容を見る事ができます。また、VB開発環境のメニューから、
[表示]-[ローカルウィンドウ]を使うと、変数の中身を一覧できます。


==============
さて、本題。

まず、
>  Dim Path As String    '以下絶対パス取得コード
この変数に対して、絶対パスを格納しているようですが、
その『絶対パスを格納した変数「Path」』が、その後、
どこにも使われていません。折角、絶対パスを格納したのに、
それを利用しないのであれば、何の意味もありませんよね。(^_^;)

次に、
>  Dim S As String
>  S = Text4.Text
>  On Error GoTo Err_Hendle    '以降、エラーが出たらErr_Hendle:以下の処理
>  If S = "" Then     'ファイルの存在チェック
というコードを書いておられますが、このコードで行われるのは
『ファイルの存在チェック』ではなく、
『Text4.Textの中身が空かどうかのチェック』になってしまっています。


そもそも、「Dir関数」は、一体、どこに行ってしまったのでしょうか?

編集 削除
YOKO  2003-08-18 17:53:00  No: 108120  IP: [192.*.*.*]

魔界の仮面弁士様  いつも有難うございます。
エクセル項目(イメージ:ファイル名)→ Data1→ Text4.text→ Picture1 の流れで画像を表示するのは分かっているのですが、エクセル項目にはファイル名(例pap.jpg)だけがが記入されているので Text4.textを調べればいいと思っていたのですが、それではいけないのでしょうか。 Dir関数を使ってフォイルの存在を調べた後 
Dim S As String
S = Text4.Text
とどのようにしたら関連づけられるかが分かりません。
それと「 On Error GoTo Err_Hendle」のコードは「If」と「Else」それぞれのケースごとにいれるべきでしょうか。
ファイルメーカーでのデーターベースは少し扱っていますが、VBは全く初めてで、
http://www.center.fks.ed.jp/08joho/download/    Visual Basic入門・応用  (638KB)
からソースコードをいただいてまねごとから始めています。デバッグの事なども今回初めて知りました。魔界の仮面弁士様には感謝の気持ちでいっぱいです。こんな私ですけれどよろしくご指導お願いします。

編集 削除
魔界の仮面弁士  2003-08-18 21:44:11  No: 108121  IP: [192.*.*.*]

> エクセル項目(イメージ:ファイル名)→ Data1→ Text4.text→ Picture1 の流れで
もしかして、Dataコントロールを使って、Excelファイルを読み込んでいるのかな?


> (例pap.jpg)だけがが記入されているので Text4.textを調べればいいと思っていたのですが、
「Text4.Textを調べれば良い」——それは確かにその通りです。
でも、先の(2003/08/17 20:31:58分の)投稿では、肝心なその
「調べる」ためのコードが書かれていませんよ。(^^;)


> Dir関数を使ってフォイルの存在を調べた後 
……あれ? どこで調べたのでしょうか?(^_^;)
そもそも、先の(2003/08/17 20:31:58分の)投稿では、
Dir関数がどこにも使われていないように見受けられるのですが……。


> Dim S As String
> S = Text4.Text
> とどのようにしたら関連づけられるかが分かりません。

1) 『変数 Path に絶対パスを格納する部分』のコードは、とりあえずOKです。
2) 絶対パスを指定したまでは良いですが、変数 Path が、その後使用されていません。
3) 変数 Path を Dir関数の引数に指定して、その戻り値を参照してください。
  先に書いたように、Dir関数が空の文字列を返すかどうかで、
  『ファイルが存在するかどうか』を調べる事ができます。
4) 「ファイルが存在した時」にだけ、LoadPictureを利用するようにします。
  この時、不正な画像ファイルが指定された時に備えて、On Error ステートメントで
  エラートラップ処理を行う必要があります。


> それと「 On Error GoTo Err_Hendle」のコードは「If」と「Else」それぞれのケースごとにいれるべきでしょうか。
基本的に、On Error は『エラーの発生する可能性のある場所』の直前に「だけ」配置し、
『エラーが発生しないと思われる場所』では、「On Error GoTo 0」にて
「トラップを解除しておく」のが常套手段です。

例えば、この部分の処理のイメージとしては、

Private Sub Command1_Click()
      :
  On Error GoTo Err_Handle
  Set Picture1.Picture = LoadPicture(ここにファイル名を指定)
  On Error GoTo 0
      :
  Exit Sub
Err_Handle:
      :
  ここにエラー時の処理を記述
      :
End Sub

か、もしくは、

Private Sub Command1_Click()
      :
  On Error Resume Next
  Set Picture1.Picture = LoadPicture(ここにファイル名を指定)
  If Err.Number <> 0 Then
          :
      ここにエラー時の処理を記述
          :
  End If
  On Error GoTo 0
      :
End Sub

のいずれかの形態となるでしょう。  


> デバッグの事なども今回初めて知りました。
とにかく、『ヘルプ(MSDNライブラリ)』を読んでください。
デバッグの方法も、そこに書かれていますよ。

今回の場合、特に、

[Visual Studio 6.0 ドキュメント]
└[Visual Basic ドキュメント]
  └[Visual Basic の使用方法]
    └[プログラミング ガイド]
      └[Visual Basic を使ってできること]
        └[コードのデバッグおよびエラー処理]

の下にある項目は、一通り目を通して(そして実際に試して)おく事を強くお奨めします。
(もし、ヘルプをインストールしていないなら、必ずインストールしておいて下さいね)

編集 削除
YOKO  2003-08-19 04:25:52  No: 108122  IP: [192.*.*.*]

魔界の仮面弁士様  
>もしかして、Dataコントロールを使って、Excelファイルを読み込んでいるのかな?
はい、Dataコントロールを使って、Excelファイルを読み込んでいます。
Dim S As String
   S = Dir("Path")
  If S = "" Then     'ファイルの存在チェック
    On Error GoTo Err_Hendle    '以降、エラーが出たらErr_Hendle:以下の処理
  Else
    On Error GoTo Err_Hendle    '以降、エラーが出たらErr_Hendle:以下の処理
    Set Picture1.Picture = LoadPicture(App.Path & "\" & Text4.Text)
    Picture1.Visible = True
    On Error GoTo 0
    Exit Sub    'エラーが出なければプロシージャを抜ける
 End If

Err_Hendle:
     MsgBox "画像がありません"
     Set Picture1.Picture = LoadPicture(App.Path & "\non.jpg")
     Picture1.Visible = True
このコードで
Dim S As String
S = Dir("Path") 
If S = "" Then
のコードで Dir("Path") の戻り値を参照する形でしてみましたが、一行ずつデバッグをかけると
If S = "" Then  のところで "" のままで値が返されてなくて、 画像があるのにErr_Hendle:へ飛びます。
S = Text4.text  にすると値が返されていて画像がない場合や違う形式の場合は Err_Hendle:へ、画像がある場合には画像が表示されました。 Dirの戻り値をIf関数で参照する方法をどこかで見た記憶がありますのでやってみましたが。これは間違いですか。
もう、お盆休みも今日で終わりになります。この一週間つめて取り組んできましたが後はぼちぼちやるしかありません。頑張ります。とても有意義なお盆休みでした。
私のようなドシロートに丁寧にお教え頂いて、魔界の仮面弁士様には本当に、本当に、感謝しております。有難うございました。

編集 削除
魔界の仮面弁士  2003-08-19 10:32:58  No: 108123  IP: [192.*.*.*]

>   Dim S As String
>   S = Dir("Path")

「変数」と「リテラル(コード中に書かれた固定値)」を区別してください。

例えば、
  'パターン A
  If Dir("C:\TEST.TXT") = "" Then
ですとか、あるいは、
  'パターン B
  S = Dir("C:\TEST.TXT")
  If S = "" Then
もしくは、
  'パターン C
  Path = "C:\TEST.TXT"
  S = Dir(Path)
  If S = "" Then
などのように書いた場合、これらは「C:\TEST.TXTという名前のファイルの存在確認」を
行っている事になります。これらは正しいコード例です。(ここまではわかりますか?)


ところが、これを
  'パターン D
  Path = "C:\TEST.TXT"
  S = Dir("Path")
  If S = "" Then
のようにした場合は、これは間違ったコード例となります。

なぜならば、これでは『変数Pathに格納されているパス(C:\TEST.TXT)』ではなく、
『"Path" という名前のファイル』の存在確認を行っている事になるからです。

これらの違いは、とても重要な部分ですので、確実に把握しておくようにしてください。

# パターンA, B では、"C:\TEST.TXT"というリテラル値を、Dir関数にて問い合わせています。
# パターンC では、Path という変数に格納された値("C:\TEST.TXT")を、Dir関数にて問い合わせています。
# パターンD では、"Path" というリテラル値を、Dir関数にて問い合わせています。


>   If S = "" Then     'ファイルの存在チェック
>     On Error GoTo Err_Hendle    '以降、エラーが出たらErr_Hendle:以下の処理
>   Else
>     On Error GoTo Err_Hendle    '以降、エラーが出たらErr_Hendle:以下の処理
>     Set Picture1.Picture = LoadPicture(App.Path & "\" & Text4.Text)

S ≠ "" の際は、LoadPicture() でエラーになる可能性があるので、その直前で
On Error を行うのは、処理としては非常に正しいですね。
しかし、S = "" の際にまで On Error を行うのは、適切とは言えません。

決して、上記の On Error の使い方が 間違っているというわけではないのですが、
昨晩にも回答しましたように、エラー処理は『エラーが発生する可能性のある箇所』にだけ
適用するようにしてください。

なぜなら、エラートラップの範囲が広すぎると、どこでエラーになったのが
不明瞭になるため、(初心者のうちは)デバッグが困難になるからです。

# 強固なシステムを組むために、広い範囲に On Error をかけるという事は、
# 最終的には間違いではありませんが、開発中の時点では、
# On Error の範囲を、できるだけ狭い範囲に留めておいた方が無難でしょう。


> If S = "" Then  のところで "" のままで値が返されてなくて、 
S が 空になっている……この事はすなわち、
『S に値を格納している部分に問題がある』という事実を指しています。

なぜ、Sが空になってしまうかというのは、今回の回答でも述べましたように、
「S = Dir("Path")」という記述に問題があるためです。


> 画像があるのにErr_Hendle:へ飛びます。
実は、Err_Hendle:』ラベル行は、エラーがあった時にだけ処理されるわけではありません。
ラベル行は、単なる「見出し」に過ぎません。本に挟む「しおり」のような物です。

On Errorによって、『エラーが発生したら、Err_Hendleという「しおり」の位置に飛べ』と
指示されてはいますが、別にエラーがおきなくても、最初から順次実行されていけば、
いずれは、Err_Hendle行の位置も処理されるというわけです。

ですから通常は、その直前などに、「Exit Sub」などといったコードを書いておき、
エラー処理ブロックが実行されないようにするのが通例となっています。
もしくは、On Error GoTo〜のかわりに『On Error Resume Next』構文を使うか、ですね。


> Dirの戻り値をIf関数で参照する方法をどこかで見た記憶がありますのでやってみましたが。これは間違いですか。
処理として、『Dirの戻り値をIf関数で参照する』というのは正しいのですが、
肝心の「Dir関数に指定した文字列」自体が間違っていたため、望むべき結果は得られません。(^_^;)


> この一週間つめて取り組んできましたが後はぼちぼちやるしかありません。頑張ります。
是非とも頑張って、現在のコードを完璧に完成させてみてくださいね。

# 私が、正解のコード例を書いてしまえば、数行のやりとりで済んだのでしょうが、
# それですと、VBを本当に「理解」するには至らないであろうろかうと思い、
# あえて、コードの間違いの指摘と、間違いの理由の解説のみに留めておき、
# コーディングは、あくまで御自身で行っていただけるように誘導していたつもりです。

VBを理解するまでは大変かも知れませんが、一度わかり始めてしまうと、あとはスムーズに進みますよ。

編集 削除