Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Excel 2016)
Yahoo!メールを使った一括送信のプログラムについて、分からない箇所があります。【パート2】
投稿日時: 20/05/02 05:55:41
投稿者: かつん

先日はお世話になりました。
今回質問させていただく内容は、先日こちらでお聞きしたプログラムの別の分からない箇所についてです。
※前回の質問はこちら:https://www.moug.net/faq/viewtopic.php?t=79241
 
インプレス社の、「Excel VBAでIEを思いのままに操作できるプログラミング術」という書籍内にあるYahoo!メールを使った一括送信のプログラムについて分からないところがあります。先日、インプレス社様に分からない箇所を質問したのですが、「掲載しておりますサイト、サービスについては本書の発行当時から再三の仕様変更が行われており、現時点では検証およサポートが非常に難しくなっております。」との回答でしたので、解決には至っておりません。
 
Yahoo!メールの「宛先」、「件名」、「本文」それぞれにソースコード内の内容を反映させます。特にエラーなく動きます。ただ、「宛先」に反映させる部分のソースコードで分からない箇所があります。
・以下のソースコードは、Yahoo!メールのメール作成画面(最初の画面から、「メールの作成」ボタンを押下して表示される画面)で実行するものです。
・Yahoo!メールのバージョンは、2.0.1.447
・ブラウザはInternet Explorer11、バージョンは、11.719.18362.0
 
 
//以下、該当部分のソースコード//

Public Sub sendMail()
	Dim ie As InternetExplorer
	Set ie = getIE("Yahoo!メール")
	Dim htdoc As HTMLDocument
	Set htdoc = ie.document

	htdoc.getElementById("to-field").Value = "xxxxxxxxxxxxxxxxxxxxxxxxx@yahoo.co.jp"
      htdoc.getElementById("subject-field").Value = "題名テスト"

    
'INPUTタグに入力したアドレスを、フォーカスが外れたときに別要素として追加する、という内部処理への対応
'◇分からない箇所◇
       Dim lbl
   	For Each lbl In htdoc.getElementsByTagName("LABEL")
    	  If lbl.innerText = "To:" Then
      	    lbl.Click
            htdoc.getElementById("to-field").Blur
            Exit For
          End If
        Next
'◇分からない箇所終わり◇
End Sub

Private Function getIE(arg_title As String) As InternetExplorer
    Dim ie As InternetExplorer
    Dim sh As Object
    Dim win As Object
    Dim document_title As String
    
    Set sh = CreateObject("shell.Application")
    For Each win In sh.Windows
        document_title = ""
        On Error Resume Next
        document_title = win.document.Title
        On Error GoTo 0
        
        If InStr(document_title, arg_title) > 0 Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set getIE = ie
End Function
//ソースコード終わり//
 
 
宛先のアドレスの文字数が長いと、「To:」欄に途中までしか何故か入力されません。それが、分からない箇所で示した部分のコードが実行されると途中で止まっていたアドレスが全部入力されます。この部分は何をしているのですか?インプレス社の説明コメント「'INPUTタグに入力したアドレスを、フォーカスが外れたときに別要素として追加する、という内部処理への対応」の意味もよく分かりません。
 
Labelタグのクリックではなく、下記のように「To:」を直接クリックしても上手く行きません。具体的には、「To:」のクリックで、それまでグレーアウトしているような状態から解除される。しかしBlurをしても無反応。結局、アドレスは途中までしか入力されていない。となってしまいます。
htdoc.getElementById("to-field").Click
htdoc.getElementById("to-field").Blur
 
 
以上、お手数をおかけしますが何方かご説明いただけると幸いです。
よろしくお願いいたします。

回答
投稿日時: 20/05/03 15:25:54
投稿者: 月

かつん さんの引用:
宛先のアドレスの文字数が長いと、「To:」欄に途中までしか何故か入力されません。それが、分からない箇所で示した部分のコードが実行されると途中で止まっていたアドレスが全部入力されます。この部分は何をしているのですか?インプレス社の説明コメント「'INPUTタグに入力したアドレスを、フォーカスが外れたときに別要素として追加する、という内部処理への対応」の意味もよく分かりません。

blurイベントを発生させています。
blurイベントはフォーカスを失った時に発生するイベントです。
 
Element: blur イベント
https://developer.mozilla.org/ja/docs/Web/API/Element/blur_event
 
ソースは追っていませんが、To欄がフォーカスを失った時に少なくとも2つのことが行われています。
 
1. 入力されたメールアドレスを青い四角で囲う
2. 入力されたメールアドレスをvalueとした<input>タグを追加する
 
To欄を右クリックして[要素の検査]をクリックすると、開発者ツールが開いてDOM ExplorerでTo欄の<input>タグが選択されると思います。
その<input>タグを含む<ul>タグの中身が、フォーカスを失う前と後で以下のように変化します。
それが「INPUTタグに入力したアドレスを、フォーカスが外れたときに別要素として追加する」の意味で、そのためにblurイベントを発生させているのだと思います。
 
実行前:
<ul>
  <li>
    <input id="to-field">

実行後:
<ul>
  <li>
    <span>
    <input value="<xxxxxxxxxxxxxxxxxxxxxxxxx@yahoo.co.jp>">
  <li>
    <input id="to-field">

投稿日時: 20/05/04 13:30:32
投稿者: かつん

月さん
 
前回に続きありがとうございます。
宛先欄にフォーカスしている時、フォーカスを外した時それぞれをDOM Explorerで確認・比較しました。仰る通りの違いを確認することができました。

'INPUTタグに入力したアドレスを、フォーカスが外れたときに別要素として追加する、という内部処理への対応

ということは、yahoo!メールの仕様として宛先欄に入力されたアドレスは、フォーカスが外れた時に別要素(新たなinputタグのvalue値)として追加され、それが新たに宛先欄に入る(再度アドレスを宛先欄に上書きしているイメージ?)という考え方でいいのですかね?
そして、その様な仕様であるから、@宛先欄にフォーカスする、ABlurでフォーカスを外して、新たに追加したinputタグのvalue値を宛先欄にセットするというイベントを発生させた。という認識であっていますでしょうか?
 
  Dim lbl
   	For Each lbl In htdoc.getElementsByTagName("LABEL")
    	  If lbl.innerText = "To:" Then
      	    lbl.Click               '@ 
            htdoc.getElementById("to-field").Blur 'A
            Exit For
          End If
        Next

回答
投稿日時: 20/05/04 15:25:01
投稿者: 月

かつん さんの引用:
yahoo!メールの仕様として宛先欄に入力されたアドレスは、フォーカスが外れた時に別要素(新たなinputタグのvalue値)として追加され、それが新たに宛先欄に入る(再度アドレスを宛先欄に上書きしているイメージ?)という考え方でいいのですかね?

はい、そうですね。
To欄はあくまで入力用で、入力されたメールアドレス1つにつき<li>が1つ追加され、その中に<span>と<input>があります。
青い四角で囲われているメールアドレスは<span>の方です。
 
かつん さんの引用:
そして、その様な仕様であるから、@宛先欄にフォーカスする、ABlurでフォーカスを外して、新たに追加したinputタグのvalue値を宛先欄にセットするというイベントを発生させた。という認識であっていますでしょうか?

はい、良いと思います。
ちょっと補足すると、"To:"と書かれたラベルをクリックすることでTo欄の<input>にフォーカスさせています。
<label>のfor属性がTo欄の<input>のidを指しているのでこのようなことができます。ラベルを手動でクリックしても同じことが起きます。
 
htdoc.getElementById("to-field").Focus

代わりにこうしても良さそうな気がしましたが効かないですね。

回答
投稿日時: 20/05/04 16:02:39
投稿者: 月

月 さんの引用:

htdoc.getElementById("to-field").Focus

代わりにこうしても良さそうな気がしましたが効かないですね。

htdoc.parentWindow.Focus
htdoc.getElementById("to-field").Focus
htdoc.getElementById("to-field").Blur

これでできました。
2行目はFocusの代わりにClickでもOKでした。

投稿日時: 20/05/05 05:48:36
投稿者: かつん

月 さんの引用:

htdoc.parentWindow.Focus
htdoc.getElementById("to-field").Focus
htdoc.getElementById("to-field").Blur

これでできました。
2行目はFocusの代わりにClickでもOKでした。

試してみました。ただ、1行目の「htdoc.parentWindow.Focus」のみで行けちゃいますね。
 
htdoc.getElementById("to-field").Value = "xxxxxxxxxxxxxxxxxxxxxxxxx@yahoo.co.jp"

で、途中までアドレスがTo:欄に入り、
htdoc.parentWindow.Focus

で、残りの部分のアドレスが入り、青い四角で囲まれる。まで行くので、それ以降の.Focus、.Blurしなくても問題無いですね。何でそんな挙動するのかよく分かりませんが。htdoc.parentWindow.Focusをする事で、To:欄からFocusが外れ、Blurイベントが発生したからですかね?
 
それにしても、何で1発でアドレスが入らないのですかね?1発で入らないから、Blurイベントを発生させているのですかね?

回答
投稿日時: 20/05/05 08:08:47
投稿者: 月

かつん さんの引用:
試してみました。ただ、1行目の「htdoc.parentWindow.Focus」のみで行けちゃいますね。

To欄にカーソルを置いて実行するとそうですね。
ただ、件名など他のところにカーソルを置いて実行すると「htdoc.parentWindow.Focus」だけではうまくいかないですね。
 
かつん さんの引用:
htdoc.parentWindow.Focusをする事で、To:欄からFocusが外れ、Blurイベントが発生したからですかね?

そうだと思います。
 
かつん さんの引用:
それにしても、何で1発でアドレスが入らないのですかね?1発で入らないから、Blurイベントを発生させているのですかね?

To欄として見えているのは実は<input>ではなく<ul>の親の<div>で、この<div>は幅が480pxあります。
それに対して<input>は幅が100ちょっとしかないのですが、入力した文字に合わせて幅を広げています。
<input>にはkeydownとkeyupのイベントも設定されていて、このどちらかで幅を広げる処理を行っているのだと思います。
 
htdoc.getElementById("to-field").Value = "xxxxxxxxxxxxxxxxxxxxxxxxx@yahoo.co.jp"

valueにセットするだけではイベントが発生しないので、幅が広がりません。

回答
投稿日時: 20/05/05 12:31:57
投稿者: 月

月 さんの引用:
<input>にはkeydownとkeyupのイベントも設定されていて、このどちらかで幅を広げる処理を行っているのだと思います。

keyupイベントを直接発生させると幅が広がりました。
 
htdoc.getElementById("to-field").Value = "xxxxxxxxxxxxxxxxxxxxxxxxx@yahoo.co.jp"
htdoc.getElementById("subject-field").Value = "題名テスト"

Dim evt As IDOMEvent
Set evt = htdoc.createEvent("HTMLEvents")
evt.initEvent "keyup", True, True
htdoc.getElementById("to-field").dispatchEvent evt

ただ、このイベントを拾って幅を広げているのは<input>に登録されているイベントリスナではなく、その上位の<div class="compose-header">に登録されているイベントリスナのようです。
ChromeでDeveloper Toolsを開いてイベントリスナを削除してみるとわかります。

投稿日時: 20/05/06 08:05:20
投稿者: かつん

月 さんの引用:
ただ、このイベントを拾って幅を広げているのは<input>に登録されているイベントリスナではなく、その上位の<div class="compose-header">に登録されているイベントリスナのようです。
ChromeでDeveloper Toolsを開いてイベントリスナを削除してみるとわかります。

 
試してみました。イベントリスナという概念自体知りませんでしたが、どういうものか何となく分かりました。勉強になります。仰る通りの挙動をしました。削除前は、To:欄に長いアドレスを手入力すると、入力欄を目一杯利用するので、右に広がっていきました。削除後は、To:欄のwidthの一部しか利用しないので、左端の狭いスペースにしか表示されませんでした。
 
 
そして、ここまでの月さんとのやり取りを振り返ると一つ疑問が出てきます。
Blurイベントでフォーカスを外すことで、新たなinputタグのvalue値が宛先欄に入り、青い四角で囲まれるという挙動をする。ここまでは分かるのですが、下記のコード"のみ"ではフォーカスが外れたことにはならないということなのですかね?
 
  htdoc.getElementById("to-field").Value = "xxxxxxxxxxxxxxxxxxxxxxxxx@yahoo.co.jp"
  htdoc.getElementById("subject-field").Value = "題名テスト"

 
1行目のコードでアドレスが入力され、2行目では件名の入力に移っています。ということは、To:欄からフォーカスが外れたことにならないのか?と思ったのですが、下記のコード無しで走らせると、アドレスが一部分しか入力されない(一部分しか見えない)、青い四角で囲まれない。よって、理由は分かりませんがフォーカスが外れた扱いにはならない。そして、その状態でメール送信をしようとすると、「To: 欄にあて先を入力してください。」と警告メッセージが表示されます。
 
Dim lbl
   	For Each lbl In htdoc.getElementsByTagName("LABEL")
    	  If lbl.innerText = "To:" Then
      	    lbl.Click
            htdoc.getElementById("to-field").Blur
            Exit For
          End If
        Next

 
何が言いたいのかといいますと、Blurイベントは、「To:欄のアドレスを確定させる」為のものであり、keyupイベントは、「To:欄の幅を広げる」為のものであり、役割が異なっているという認識でいいのですかね?ということが聞きたかったです。
つまり、私が先日質問させていただいた、「何で1発でアドレスが入らないのですかね?」に対する答えは、To:欄の横幅が広がらないからではなく、「宛先のアドレスが確定しないから」であると思うのです。keyupイベントは幅を広げているだけで、見た目上の変化だけであり、処理に影響は無いと思います。実際、この「Yahoo!メールを使った一括送信のプログラム」は、キーボード操作は一切無いことから、イベントが発生しないはずで、発生しなくても問題ないのではないかというのが、うんうん悩んで出した結論です。
 
長々とすみませんが、このような認識であっているのですかね?
そしてなぜ、件名:の入力に移ってもフォーカスが外れた認定されないのですかね?

回答
投稿日時: 20/05/06 13:43:21
投稿者: 月

かつん さんの引用:
下記のコード"のみ"ではフォーカスが外れたことにはならないということなのですかね?
 
  htdoc.getElementById("to-field").Value = "xxxxxxxxxxxxxxxxxxxxxxxxx@yahoo.co.jp"
  htdoc.getElementById("subject-field").Value = "題名テスト"

はい、ならないですね。
 
かつん さんの引用:
何が言いたいのかといいますと、Blurイベントは、「To:欄のアドレスを確定させる」為のものであり、keyupイベントは、「To:欄の幅を広げる」為のものであり、役割が異なっているという認識でいいのですかね?ということが聞きたかったです。

はい、その通りです。
 
かつん さんの引用:
そしてなぜ、件名:の入力に移ってもフォーカスが外れた認定されないのですかね?

.Valueへのセットでフォーカスがセットされたり外れたりするわけではないからです。
他にフォーカスがある状態で.Valueにセットしてみればわかると思います。
Excelの Range("A1").Value = "a" と同じです。

投稿日時: 20/05/07 06:04:56
投稿者: かつん

月 さんの引用:
.Valueへのセットでフォーカスがセットされたり外れたりするわけではないからです。
他にフォーカスがある状態で.Valueにセットしてみればわかると思います。
Excelの Range("A1").Value = "a" と同じです。

 
理解しました。Valueプロパティに値がセットされただけで、フォーカスは関係ないということですね。手動でTo:欄にアドレスを打ち込む場合とは異なるのですね。同じだと間違って解釈してました。
 
もう一つお聞きしたいのですが、下記のコードですが、1行目でTo:欄からフォーカスが外れるのでアドレスが有効化されます。ただ問題があり、フォーカスがIEに移るのでステップ実行(F8)だと、制御がVBEに戻れなくなり、そこでプログラムが止まってしまいます。通常のプログラムの実行(F5)であれば、最後まで走ります。この違いは何なのでしょうか?F5実行の場合は、フォーカスが他のウィンドウに移っても、内部的に自分自身に戻しているということなのでしょうか?
 
htdoc.parentWindow.Focus
htdoc.getElementById("to-field").Focus
htdoc.getElementById("to-field").Blur

回答
投稿日時: 20/05/07 13:01:07
投稿者: 月

かつん さんの引用:
ただ問題があり、フォーカスがIEに移るのでステップ実行(F8)だと、制御がVBEに戻れなくなり、そこでプログラムが止まってしまいます。

こちらでは再現しませんでした。
 
Win 10 Pro / Excel 2016 / IE 11.778.18362.0
Yahoo!メールのバージョン:2.0.1.453

投稿日時: 20/05/08 06:17:09
投稿者: かつん

月 さんの引用:

こちらでは再現しませんでした。
 
Win 10 Pro / Excel 2016 / IE 11.778.18362.0
Yahoo!メールのバージョン:2.0.1.453

 
そうでしたか。私はやはりF8実行だとIEのウィンドウが選択されるので、その後F8を押しても反応しなくなりますね。VBEのウィンドウをクリックすれば、当然有効化されるのでステップ実行を再開する事ができるのですが。なので、フリーズするとかではないので問題無いと言えば無いのですがね。それに、F5での実行であれば最後まできちんと走りますし。ただ、月さんとの違いは若干気になりますね。環境も「Win 10 Pro」と「Win 10 Home」の違いしか無いので、関係ないように思いますし。
 
質問のメイン部分は解決していますので、今日一日粘ってみて特に発見など無さそうならクローズしようと思います!

投稿日時: 20/05/09 07:16:18
投稿者: かつん

F8実行では、手動でVBEのウィンドウに制御を戻す(ウィンドウをクリック)しないとやはり続きの処理を再開出来ませんでした。そもそも上から順番にコードを実行する以上、制御がIEに移った時点で、それ以降のコードに何を書いても実行されないので、この問題はどうしようもないのかなという感じです。
 
昨日言ったように本題から派生した質問であり、本命の疑問は解決しておりますので、これで終わろうと思います。月さんありがとうございました。
 
私が学習に使っている書籍「Excel VBAでIEを思いのままに操作できるプログラミング術」も、残すところあと30ページ程になりました(結構あるな^^;)また疑問点等が出てきましたら、質問させていただきますのでよろしくお願いいたします。