WebBrowser上の文字の背景色・文字色を同時変更で時間がかかる

タグの編集
投稿者 アキラ  (社会人) 投稿日時 2020/9/8 10:29:42
WebBrowserで表示している文書の指定キーワードの背景色を変えるため、
以下のページを参考にしてうまくいきました。

http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=9299

そこで、指定キーワードの文字色も変えようと思い、
背景色設定コードの次に文字色設定コードを追加しました。

とりあえず、背景色・文字色ともに変更できたのですが、
テキスト量の多いWebページでは、処理が終わるのに非常に時間がかかります。

背景色のみ変更、または文字色のみ変更の場合は比較的早く処理が終わりますが、
以下のコードのように背景色と文字色を変更しようとすると、
フリーズしたような感じになります。(待てば処理は終わるようです。)
以下のコードは、参考ページのコードに文字色設定行を追加したものです。

    Private Sub Find(ByVal browser As WebBrowser, ByVal str As String)
         Dim Doc As mshtml.HTMLDocument       'MSHTML.HTMLDocument  
         Dim Body As mshtml.HTMLBody      'MSHTML.HTMLBody  
         Dim Range As mshtml.IHTMLTxtRange  'MSHTML.IHTMLTxtRange  
         Dim BMK As String = ""

         '検索文字列を入れておいてください。  
         If String.IsNullOrEmpty(str) Then
             Return
         End If

         Doc = DirectCast(browser.Document.DomDocument, mshtml.IHTMLDocument2)
         Body = Doc.body
         Range = Body.createTextRange

         '≫≫≫≫≫ 検索開始  
         Do While Range.findText(str)
             '最初に見つかった位置を保存しておきます。  
             If String.IsNullOrEmpty(BMK) = 0 Then

             End If
             BMK = Range.getBookmark

             '検索した語句を黄色く反転させる。  
             Range.execCommand("BackColor"False"YELLOW")    '背景色の設定(元のコード) 
             Range.execCommand("ForeColor"False"RED")       '文字色の設定(追加) 

             '論理カーソル位置を、検索した語句の末尾に移動させる。  
             Range.collapse(False)
         Loop
         '≪≪≪≪≪ 検索終了  

         'ついでに、最初に見つけた語句の位置までスクロールさせています。  
         If Not String.IsNullOrEmpty(BMK) Then
             Range.moveToBookmark(BMK)
             Range.scrollIntoView()
         End If

         '最後は一応、後始末を。  
         Range = Nothing
         Body = Nothing
         Doc = Nothing
     End Sub


指定Rangeの背景色と文字色を同時変更したい場合はどうすればよいのでしょうか?

投稿者 (削除されました)  () 投稿日時 2020/9/8 11:54:25
(削除されました)
投稿者 アキラ  (社会人) 投稿日時 2020/9/8 15:57:39
自己レスです。
 文字色→背景色の順でexecCommandを実行したら、格段に処理が速くなりました。

             '検索した語句を黄色く反転させる。    
               Range.execCommand("ForeColor"False"RED")       '文字色の設定(追加)   
               Range.execCommand("BackColor"False"YELLOW")    '背景色の設定(元のコード)   

とりあえずこれでOKのようですが、なぜこれだけで処理速度が改善したのかはさっぱり分かりません。
もしここら辺の情報をお持ちの方がいらっしゃいましたら、コメント大歓迎です。
よろしくお願いします。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/9/8 16:00:10
あぁ、懐かしいコードが出てきましたね…。

でも移植内容がちょっと不自然。コメントと処理が合致していないようです。
> If String.IsNullOrEmpty(BMK) = 0 Then

> End If
> BMK = Range.getBookmark
IsNullOrEmpty の戻り値は Integer ではなく Boolean ですし、
そもそもこれでは、If 文が何の役目も果たしていません。


これの原文は私が 2000/06/30 に VB 系メーリングリストに投稿した
VB6 向けのコードなのですが、その当時は下記のように書いていたはずなんですよね。

> '検索文字列を入れておいてください。
> If Len(Text1.Text) = 0 Then Exit Sub

> Set Doc = WebBrowser1.Document
> Set Body = Doc.Body
> Set objRange = Body.createTextRange

> '≫≫≫≫≫ 検索開始
> Do While objRange.findText(Text1.Text)
>  '最初に見つかった位置を保存しておきます。
>  If Len(BMK) = 0 Then BMK = objRange.getBookmark

>  '検索した語句を黄色く反転させる。
>  objRange.execCommand "BackColor", False, "YELLOW"

>  '論理カーソル位置を、検索した語句の末尾に移動させる。
>  objRange.collapse False
> Loop
> '≪≪≪≪≪ 検索終了

> 'ついでに、最初に見つけた語句の位置までスクロールさせています。
> If Len(BMK) Then
>  objRange.moveToBookmark BMK
>  objRange.scrollIntoView
> End If

> '最後は一応、後始末を。
> Set objRange = Nothing
> Set Body = Nothing
> Set Doc = Nothing


なお、.createTextRange や .getBookmark はプロパティではなくメソッドなので、
本来は .createTextRange() や .getBookmark() と書いた方が望ましいです。



> なぜこれだけで処理速度が改善したのかはさっぱり分かりません。

うぅむ、何故でしょうね。
順番を入れ替えた場合、outerHTML の内容が微妙に違っていたりはしますか?



とりあえず実験。短めのコンテンツなので速度検証はしておりませんが、
順番を入れ替えても HTML の内容に差は生じていませんでした。

コンテンツの内容や互換モードの設定、IHTMLTxtRange の範囲にもよるのかな。


 1⃣ 【原文】XHTML 1.1 で書かれたコンテンツ
<div style="background-Color:green">
  <label for="U"><font color="white">ログインID</font></label>
  <input id="U" name="U" size="18" value="" />
</div>


 2⃣  [1] に対して、"ログイン" の BackColor を Red にした場合。
<div style="background-Color:green">
  <label for="U">
    <font color="white">
      <FONT style="BACKGROUND-COLOR: red">ログイン</FONT>
      ID
    </font>
  </label>
  <input id="U" name="U" size="18" value="">
</div>


 3⃣ [1] に対して、"ログイン" の ForeColor を Blue にした場合。
<div style="background-Color:green">
  <label for="U">
    <font color="white">
      <FONT color="blue">ログイン</FONT>
      ID
    </font>
  </label>
  <input id="U" name="U" size="18" value="">
</div>


 4⃣ [2] に対して、ForeColor を Blue にした場合と、
    [3] に対して、BackColor を Red にした場合の結果は同じだった。
<div style="background-Color:green">
  <label for="U">
    <font color="white">
      <FONT style="BACKGROUND-COLOR: red" color="blue">ログイン</FONT>
      ID
    </font>
  </label>
  <input id="U" name="U" size="18" value="">
</div>
投稿者 アキラ  (社会人) 投稿日時 2020/9/8 17:11:09
魔界の仮面弁士様
コメントありがとうございます。
試してみたコードについては掲載されたものほぼそのままパクリでした。

僕の方でも、短いHTMLを使用してBackColor→ForeColorの順とForeColor→BackColorの順でexecCommandしてみましたが、いずれも、対象文字のouterHtmlは以下の通りでした。
(BackColorはYELLOW, ForeColorはRED)
<FONT style="BACKGROUND-COLOR: #ffff00" color=#ff0000>対象</FONT>

でも、検索対象のHTMLが大きい(検索箇所が多い)と、ForeColor・BackColorの順番の違いが
非常に顕著でビックリです。
(これは試してみると分かりますので、もじお時間がございましたらお試しください。)
テキストサイズが1MB程度のHTMLで検索+色設定を行うと、
ForeColor→BackColorの順では数秒程度で処理が終わったのですが、
BackColor→ForeColorの順だとフリーズしたような状態になります。
放っておいたら処理が終了していたみたいですが、どれくらい時間がかかったのか分かりません。
なお、検索箇所は8000くらいでした。

ForeColorはcolor属性で設定されていて、BackColorはstyle属性のBACKGROUND-COLORで
設定されていますが、この違いが影響しているのでしょうか?