Webブラウザコントロールでオブジェクトをウィンドウの上端までスクロールさせて表示させるには?

解決


FD  2008-11-12 01:06:24  No: 101269

おせわになります。

http://madia.world.coocan.jp/vb/vb_bbs/200505/200505_05050074.html
上の過去ログの、サンプルプログラムを使わせて頂いたのですが、
その結果、見事にしたいことが出来たのですが、検索された文字列がウインドウの
下の方に表示されると見にくいので、上の方に表示されるようにしようと思って、
調べていたら、MSDNの「scrollIntoView」の解説(http://msdn.microsoft.com/ja-jp/library/cc428162.aspx)に
scrollIntoViewメソッドの引数に TRUE を指定すれば出来ると書いてありました。
しかし、TRUE を指定しても上端までスクロールしてくれませんでした。
TRUE を指定しても False 指定しても下端に表示されます。
上端に表示するにはどうすればいいでしょうか?

別の方法でも構いませんので、どうかご教授のほどよろしくお願いいたします。


魔界の仮面弁士  2008-11-14 20:19:04  No: 101270

scrollIntoView そのものは、
  http://www.millionwaves.com/200501110821.html
のように動作するハズです。(引数省略時は true の動作)

> しかし、TRUE を指定しても上端までスクロールしてくれませんでした。
問題の出ているコードを提示する事はできますか?
(少なくとも、こちらで試した限りでは期待動作しています)

Option Explicit

Private WithEvents Doc As HTMLDocument

Private Sub Form_Load()
    WebBrowser1.Navigate "http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200505/05050074.txt"
    Text1.Text = "2005/05/27(金) 22:32:53"
    Option1(0).Value = True
    Option1(0).Caption = "上合わせ"
    Option1(1).Caption = "下合わせ"
    Command1.Enabled = False
End Sub

Private Sub Command1_Click()
    If Doc Is Nothing Then Exit Sub
    
    Dim oRng As IHTMLTxtRange
    Set oRng = Doc.body.createTextRange()

    If oRng.findText(Text1.Text) Then
        Dim toTop As Boolean
        toTop = Option1(0).Value
        oRng.scrollIntoView toTop
    End If
End Sub

Private Sub WebBrowser1_BeforeNavigate2(ByVal pDisp As Object, URL As Variant, Flags As Variant, TargetFrameName As Variant, PostData As Variant, Headers As Variant, Cancel As Boolean)
    Set Doc = Nothing
    Command1.Enabled = False
End Sub

Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object, URL As Variant)
    Set Doc = WebBrowser1.Document
    Command1.Enabled = True
End Sub


FD  2008-11-15 05:47:25  No: 101271

魔界の仮面弁士さん、ご回答有り難うございます。
いつも勉強させていただいております。

ご提示いただいたサンプルコードを早速試させて頂きましたが、私の環境では、オプションボタンを「上合わせ」にしても「下合わせ」にしても、下端に表示されました。
環境は「WinXP、VB5、IE6」です。

私の場合、
http://madia.world.coocan.jp/vb/vb_bbs/200505/200505_05050074.html
ここの、魔界の仮面弁士さんのコードを、ほとんどそのまま既存のIE用にしたものですが、それでも下端に表示されます。

objRange.scrollIntoView True 
この行に True を加えただけです。False に指定しても下端に表示されました。

Private WithEvents Doc As HTMLDocument
Dim IE As Object

Private Sub Form_Load()
    Text1.Text = "2005/05/27(金) 22:32:53"
    Set IE = CreateObject("InternetExplorer.Application")
    IE.Navigate2 "http://madia.world.coocan.jp/vb/vb_bbs/200505/200505_05050074.html"
    IE.Visible = True
End Sub

Private Sub Command1_Click()

    If IE Is Nothing Then Exit Sub
    
    Dim Doc As Object       'MSHTML.HTMLDocument
    Dim Body As Object      'MSHTML.HTMLBody
    Dim objRange As Object  'MSHTML.IHTMLTxtRange
    Dim BMK As String
    'Dim L As Long

    '検索文字列を入れておいてください。
    If Len(Text1.Text) = 0 Then Exit Sub
    
    Set Doc = IE.document
    Set Body = Doc.Body
    Set objRange = Body.createTextRange

    '≫≫≫≫≫ 検索開始
    'For L = 0 To 255
    '   If objRange.findText(Text1.Text) = False Then Exit For
    Do While objRange.findText(Text1.Text)
        '最初に見つかった位置を保存しておきます。
        If Len(BMK) = 0 Then BMK = objRange.getBookmark
        
        '検索した語句を黄色く反転させる。
        objRange.execCommand "BackColor", False, "YELLOW"
        
        '論理カーソル位置を、検索した語句の末尾に移動させる。
        objRange.collapse False
    Loop
    'Next L
    '≪≪≪≪≪ 検索終了

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

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

どうかご指導のほどよろしくお願いいたします。


魔界の仮面弁士  2008-11-15 06:53:59  No: 101272

> 環境は「WinXP、VB5、IE6」です。

環境によるのかな…? こちらは、WinXP Pro/SP3、VB6/SP6、IE7 です。

と言うことで、手元の Win2000 Pro/SP無、VB無、IE6/SP1 という環境で、
先ほどの http://www.millionwaves.com/200501110821.html を実行したところ、
期待通り 上/下 に移動する事を確認できました。

何が違うのだろう…。


FD  2008-11-15 15:52:25  No: 101273

魔界の仮面弁士さん、度々有り難うございます。

> 環境によるのかな…? 
そうなのですか。環境によるものなのでしたらあきらめようかと思います。
わざわざ試して下さって有り難うございました。

早速、別の方法を模索してみたのですが、TextRangeオブジェクトに
次のようなプロパティーを見つけました。
boundingLeft ,boundingTop ,boundingWidth ,boundingHeight ,offsetLeft ,offsetTop
これらはTextRangeオブジェクトを包含する矩形のサイズや位置を取得するためのものらしいのですが、
これらを使えば検索したテキストをウインドウの上端に表示できるのではないかと思い、
いろいろ試してみたのですが使い方がよくわかりませんでした。

まずTextRangeオブジェクトの絶対位置を取得して、
次に scrollTo メソッドでそこまでスクロールさせようと思ったのですが、
絶対位置を求めることができずに悩んでおります。

boundingTop が絶対位置を表すのかと思ったらそうでもないようですし、
スクロールするとマイナスの値になったりとよくわかりませんでした。

TextRangeオブジェクトの絶対位置を取得するには上のプロパティーをどう計算すればいいのでしょうか?

何度もすいませんが、よろしくお願いいたします。


Hongliang  2008-11-15 20:23:19  No: 101274

Vista / IE7 / C# + .NET 2.0 の WebBrowser コントロール+リフレクションでのレイトバインディングってマニアックな環境で色々試してみました。
どうも、ITxtRange の指す範囲が下に移動したとき、今表示しているのが ITxtRange オブジェクトの指す範囲よりも上だった場合、scrollIntoView の引数が無視されてとにかく表示できるところまでスクロールする、という動作があるようです。その結果 FALSE を設定したのと同じような挙動になる。厳密にはほかの条件があるんでしょうけれど。
お気づきの通り、offsetTop が有効に使えそうです。offsetTop は「今の表示の上端から IHTMLTxtRange の指す範囲の上端までの距離」ですから、body(IE だと DOCTYPE が宣言されてる場合 は documentElement になりますが)の scrollTop をそれだけ動かしてやればちょうど IHTMLTxtRange の指す範囲の上端が今の画面の上端にくることになります。


FD  2008-11-15 23:20:45  No: 101275

Hongliangさん、ご回答有り難うございます。
色々試して下さって有り難うございます。

教えて頂いたことをもとに下記のようにしてみた。
するとうまく表示することができた。
有り難うございました。

ただ、いろいろなサイトで試しているうちにちょっと問題が発生しました。
サイトによって、現在のスクロールバーの位置によって違う位置が表示されてしまうようです。(コマンドボタンを押すたびに位置が変わる。)

> IE だと DOCTYPE が宣言されてる場合 は documentElement になりますが
とおっしゃるように、「ownerDocument」のあとに「Body」を付けるか「documentElement」付けるかで場合分けしなければいけなくなるようなときがあるようです。
しかしその場合分けの仕方がわかりませんでした。
ウォッチウインドウで「objRange.parentElement.ownerDocument.doctype」の値を調べたのですが、
どちらの場合も Nothing になっていました。
どうやったら場合分けができるのでしょうか?

どうかよろしくお願いいたします。

Private WithEvents Doc As HTMLDocument
Dim IE As Object

Private Sub Form_Load()

    Dim url As String

''実験その1
'    Text1.Text = "Variant"
'    url = "http://madia.world.coocan.jp/vb/vb_bbs/200505/200505_05050074.html"
    
'実験その2
    Text1.Text = "Basic"
    url = "http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1320299018"
    
    Set IE = CreateObject("InternetExplorer.Application")
    IE.Navigate2 url
    IE.Visible = True
    
End Sub

Private Sub Command1_Click()

    If IE Is Nothing Then Exit Sub
    
    Dim Doc As Object       'MSHTML.HTMLDocument
    Dim Body As Object      'MSHTML.HTMLBody
    Dim objRange As Object  'MSHTML.IHTMLTxtRange
    Dim BMK As String
    'Dim L As Long

    '検索文字列を入れておいてください。
    If Len(Text1.Text) = 0 Then Exit Sub
    
    Set Doc = IE.document
    Set Body = Doc.Body
    Set objRange = Body.createTextRange

    '≫≫≫≫≫ 検索開始
    'For L = 0 To 255
    '   If objRange.findText(Text1.Text) = False Then Exit For
    Do While objRange.findText(Text1.Text)
        '最初に見つかった位置を保存しておきます。
        If Len(BMK) = 0 Then BMK = objRange.getBookmark
        
        '検索した語句を黄色く反転させる。
        objRange.execCommand "BackColor", False, "YELLOW"
        
        '論理カーソル位置を、検索した語句の末尾に移動させる。
        objRange.collapse False
    Loop
    'Next L
    '≪≪≪≪≪ 検索終了

    'ついでに、最初に見つけた語句の位置までスクロールさせています。
    If Len(BMK) Then
        objRange.moveToBookmark BMK
'        objRange.scrollIntoView True 'ここに True を加えただけです。
        
        'objRange の位置情報。
        z1 = objRange.boundingLeft
        z2 = objRange.boundingTop
        z3 = objRange.boundingWidth
        z4 = objRange.boundingHeight
        z5 = objRange.offsetLeft
        z6 = objRange.offsetTop
        
'サイトによって場合分けしないといけない。
'そうしないとコマンドボタンを押すたびに位置が変わる。つまりスクロールバーの位置によって結果が変わってくる。

''「実験その1」のときは
'        cw = objRange.parentElement.ownerDocument.Body.clientWidth 'Docの表示領域のクライアント領域のサイズの幅。
'        ch = objRange.parentElement.ownerDocument.Body.clientHeight 'Docの表示領域のクライアント領域のサイズの高さ。
'        z7 = objRange.parentElement.ownerDocument.Body.scrollLeft '現在の水平スクロールバーの位置
'        z8 = objRange.parentElement.ownerDocument.Body.scrollTop '現在の垂直スクロールバーの位置

'「実験その2」のときは
        cw = objRange.parentElement.ownerDocument.documentElement.clientWidth 'Docの表示領域のクライアント領域のサイズの幅。
        ch = objRange.parentElement.ownerDocument.documentElement.clientHeight 'Docの表示領域のクライアント領域のサイズの高さ。
        z7 = objRange.parentElement.ownerDocument.documentElement.scrollLeft '現在の水平スクロールバーの位置
        z8 = objRange.parentElement.ownerDocument.documentElement.scrollTop '現在の垂直スクロールバーの位置
        
        'スクロールさせる。検索語の右端がウインドウに収まるように調節している。
        objRange.parentElement.ownerDocument.parentWindow.scrollTo z7 + z5 - cw + z3, z8 + z6
    
    End If

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


Hongliang  2008-11-16 01:14:13  No: 101276

そんなに沢山のページを調べたわけではないので、DOCTYPE の有無(というか後方互換モードかどうか)以外で何か問題があるかどうかは確認していません。
> サイトによって、現在のスクロールバーの位置によって違う位置が表示されてしまうようです
と言うのも(後方互換モード以外に)現象を把握できませんのでコメントできません。

取りあえず、documentElement を使うかどうかは
http://www.google.com/search?hl=ja&lr=lang_ja&oe=utf8&q=body+documentelement
この辺を調べてください。


FD  2008-11-16 08:45:35  No: 101277

Hongliangさん、有り難うございました。

compatMode を調べることで場合わけができるようになりました。

compatMode が "BackCompat" のときは、body になって、
compatMode が "CSS1Compat" のときは、documentElement になるようです。

ただそれでもときどきずれるときがあります。
それは、例えば、ページ上にテキストエリアが存在するようなときです。
テキストエリアのスクロールバーをスクロールしてから全体をスクロールしないといけないみたいなので。
ここまでくると大変なので、もう上端に表示させることはあきらめようかと思います。
scrollIntoViewで下端に表示させたあと、だいたい10行分くらい上にスクロールしてやるというよな感じにしようと思います。

Hongliangさん、魔界の仮面弁士さん、いろいろと有り難うございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加