C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: ウェブブラウザ上に表示したページのデータを検索・置換


(過去ログ 71 を表示中)

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■41265 / inTopicNo.1)  ウェブブラウザ上に表示したページのデータを検索・置換
  
□投稿者/ RT (124回)-(2009/09/16(Wed) 18:23:17)

分類:[.NET 全般] 

こんにちは、RTと申します。
たびたびお世話になっております。

質問なのですが、まず、リッチテキストボックス上に表示したデータを検索・置換する事は出来ました。

ですが、ウェブブラウザ上に表示したページのデータを検索・置換する方法がわかりません。

ウェブブラウザには、SelectionLengthやSelectedText等のプロパティがないので、リッチテキストボックスの様には、うまくいかないようです。

なにかいい方法はないでしょうか?アドバイスお願いします。
引用返信 編集キー/
■41272 / inTopicNo.2)  Re[1]: ウェブブラウザ上に表示したページのデータを検索・置換
□投稿者/ Hongliang (467回)-(2009/09/16(Wed) 20:08:26)
「ウェブブラウザ」は、自分のアプリケーションのフォーム上に配置した WebBrowser コントロールって事で良いですね?

.NET の標準ライブラリではサポートしていないので、まず参照の追加で COM の Microsoft HTML Object Library を参照してください。
WebBrowser の Document プロパティの DomDocument プロパティを IHTMLDocument2 インターフェイスに DirectCast できるようになります。
あとは selection -> createRange(取得したのを IHTMLTxtRange に DirectCast)で IHTMLTxtRange を取得し、その IHTMLTxtRange に対して findText とか pasteHTML とか、という手順になります。
findText が、RichTextBox における Find メソッドの呼び出し及び SelectionStart/SelectionLength の設定に該当します。
// IHTMLTxtRange の場合、選択箇所を反転表示させるにはさらに select メソッドの呼び出しも必要ですが。
htmlText で選択箇所の HTML を取得し、pasteHTML で選択箇所に上書きで HTML を貼り付けます。
引用返信 編集キー/
■41333 / inTopicNo.3)  Re[2]: ウェブブラウザ上に表示したページのデータを検索・置換
□投稿者/ RT (125回)-(2009/09/17(Thu) 22:41:10)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
//using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace webRewriter
{
//[検索]用、[置換]用の列挙型(フラグ用)
public enum dialogMode
{
Find,
Replace
}


public partial class findDialog : Form
{
//処理対象となる TextBox のインスタンスを保持
private RichTextBox _textBox;

//[検索]用のダイアログボックスを表示するか、
//[置換用のダイアログボックス]を表示するかのフラグ
private dialogMode _mode;

private int findStartIndex = 0;
private int findCount = 0;
private string dialogTitle = "";

#region Constructor //コンストラクタ

public findDialog()
{
InitializeComponent();
}

public findDialog(RichTextBox txtBox)
{
InitializeComponent();
_textBox = txtBox;
}

public findDialog(dialogMode mode)
{
InitializeComponent();
Mode = mode;
}

public findDialog(dialogMode mode, RichTextBox txtBox)
{
InitializeComponent();
_textBox = txtBox;
Mode = mode;
}

#endregion

#region EventHandler //イベントハンドラ

//[キャンセル]ボタンの処理
private void cancelButton_Click(object sender, EventArgs e)
{
this.Close();
this.Dispose();
}

//[検索]ボタンの処理
private void findButton_Click(object sender, EventArgs e)
{
replaceNextButton.Enabled = ExecFind();
}

//[置換]ボタンの処理
private void replaceNextButton_Click(object sender, EventArgs e)
{
if (_textBox.SelectionLength > 0) _textBox.SelectedText = ReplaceTextBox.Text;
replaceNextButton.Enabled = ExecFind();
}

//検索開始位置ラジオボタンの処理
private void findPosition_Radio_CheckedChanged(object sender, EventArgs e)
{
//対応するラジオボタンの常に反対の値を設定
topPosRadio.Checked = (currentPosRadio.Checked != true);
}

#endregion

#region Methods //メソッド

//検索処理
private bool ExecFind()
{
//TextBox コントロール内の文字列
string editString = _textBox.Text;

//検索を行う文字列
string findString = findTextBox.Text;

//検索を行う文字列の長さ
int findStringLength = findString.Length;

//検索開始位置の設定([先頭から]ラジオボタンが選択されている場合は 0 = 先頭 を設定)
int findPoint = (topPosRadio.Checked) ? 0 : _textBox.SelectionStart;

//二回目以降の検索位置の指定
findStartIndex = (findStartIndex == 0) ? findPoint : findStartIndex;

//検索処理
findPoint = editString.IndexOf(findString, findStartIndex, (LgSmCheckBox.Checked) ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase);

//検索する文字列が見つからなかった場合
if (findPoint == -1)
{
const string MSGBOX_STRING = "ドキュメントの最後まで検索しました。\nもう一度先頭から検索しますか?";
string msbox_NothingWord = "\"" + findString + "\"は見つかりません。";
if (findCount != 0)
{
if (MessageBox.Show(this, MSGBOX_STRING, dialogTitle,
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
ResetFindPosition();
}
else
{
this.Close();
this.Dispose();
}
}
else
{ //検索の開始位置が[現在位置から]の場合は先頭から検索しなおすかいちおう確認
if (currentPosRadio.Checked)
{
string msgbox_string = "現在位置から" + MSGBOX_STRING;
if (MessageBox.Show(this, msgbox_string, dialogTitle,
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
ResetFindPosition();
}
else
{
this.Close();
this.Dispose();
}
}
else
{
MessageBox.Show(this, msbox_NothingWord, dialogTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
return false;
}
else
{
//見つかった文字を選択
_textBox.Select(findPoint, findStringLength);

//TextBox が選択された文字列を表示するようキャレットを移動
_textBox.ScrollToCaret();

//[次を検索] ボタンをクリックされた際の検索開始位置を設定
findStartIndex = findPoint + findStringLength;

//検索がヒットした回数をカウント
findCount++;

//テキストボックスにフォーカスをあてる
_textBox.Focus();
return true;
}
}

//TextBox の検索位置をリセットする処理
private void ResetFindPosition()
{
findStartIndex = 0;
findCount = 0;
_textBox.SelectionStart = 0;
_textBox.Select(0, 0);
_textBox.Focus();
}
#endregion

#region property //プロパティ

//処理対象となる TextBox のインスタンス設定するためのプロパティ
public RichTextBox textBox
{
get { return _textBox;}
set { _textBox = value; }
}

//[検索]用のダイアログボックスを表示するか、
//[置換用のダイアログボックス]を表示するかのプロパティ
public dialogMode Mode
{
get { return _mode; }
set {
const string DIALOGTITLE_FIND = "検索";
const string DIALOGTITLE_REPLACE = "置換";
_mode = value;
if (_mode == dialogMode.Find)
{
dialogTitle = DIALOGTITLE_FIND;
ReplacePanel.Visible = false;
}
else
{
dialogTitle = DIALOGTITLE_REPLACE;
ReplacePanel.Visible = true;
}
this.Text = dialogTitle;
}
}

#endregion

private void replaceAllButton_Click(object sender, EventArgs e)
{
replaceNextButton.Enabled = ExecFind();
while (_textBox.SelectionLength > 0)
{
_textBox.SelectedText = ReplaceTextBox.Text;
replaceNextButton.Enabled = ExecFind();
}
}






}
}

 リッチテキストの場合は↑のコードでうまく行きます。↑のコードのリッチテキストに関する記述をウェブブラウザに変えて、エラーが出たところに修正を加えて使えるようにしたいと思っています。

教えて頂いたアドバイスを参考に↓のようなコードを使おうとしました。
HtmlDocument doc = webBrowser1.Document;
mshtml.IHTMLDocument2 doc2 = doc.DomDocument as mshtml.IHTMLDocument2;
mshtml.IHTMLTxtRange textRange = ((mshtml.IHTMLBodyElement)doc2.body).createTextRange();
textRange.findText();

しかし、別のフォームで、webBrowser1のようなコントロール名を使うとエラーが出ます。
また、findTextの第一引数には、検索して見つかった選択状態のテキストを指定したいのですが、
SelectedTextのような、プロパティが、ウェブブラウザにはないようです。

↑のようなリッチテキストで動くコードを、ウェブブラウザ仕様にして、動かす事は可能なのでしょうか?
引用返信 編集キー/
■41334 / inTopicNo.4)  Re[3]: ウェブブラウザ上に表示したページのデータを検索・置換
□投稿者/ Hongliang (468回)-(2009/09/17(Thu) 23:30:17)
>  リッチテキストの場合は↑のコードでうまく行きます。↑のコードのリッチテキストに関する記述をウェブブラウザに変えて、エラーが出たところに修正を加えて使えるようにしたいと思っています。
>
> ↑のようなリッチテキストで動くコードを、ウェブブラウザ仕様にして、動かす事は可能なのでしょうか?

RichTextBox と WebBrowser/mshtml では設計思想が全然違うので、「エラーが出たところに修正を」では済まないでしょうね。
// 長々コード書かれても私を含む大抵の人は読む気がしないので、説明するなら日本語で簡潔に処理を説明する方がいいですよ。

> しかし、別のフォームで、webBrowser1のようなコントロール名を使うとエラーが出ます。

そりゃ「別のフォーム」に webBrowser1 という変数がなければエラーになるでしょうが……。
ちらっと見た感じ、RichTextBox 用検索ダイアログクラスではコンストラクタで RichTextBox を渡しているようですし、WebBrowser 用検索ダイアログクラスならコンストラクタで WebBrowser を渡すとか。
まあ、普通に考えればダイアログは共通にするでしょうから、ダイアログにコントロール渡すなんて共通化の逆を行く手法はダメでしょうね。
この辺は設計の問題ですが、私なら取り敢えず簡単に、
・IFindTarget インターフェイスと、それを実装する RichTextBoxFinder / WebBrowserFinder を作成
・IFindTarget インターフェイスには Find メソッドと Replace メソッドを用意
・各 Finder はコンストラクタでコントロールを受け取ってフィールドに保持、Find と Replace を実装
・FindDialog クラスのコンストラクタは IFindTarget を受け取りフィールドに保持するようにする
・FindDialog のボタンイベントなどに応じて IFindTarget.Find や Replace を呼び出す
みたいな形にするかな。
// それともコントロールのインスタンスを Form 外に出すのを気持ち悪がってイベントでやっちゃうかな?

> また、findTextの第一引数には、検索して見つかった選択状態のテキストを指定したいのですが、
> SelectedTextのような、プロパティが、ウェブブラウザにはないようです。
htmlText や text プロパティは、findText で検索した箇所のみの情報を返します。
引用返信 編集キー/
■41335 / inTopicNo.5)  Re[4]: ウェブブラウザ上に表示したページのデータを検索・置換
□投稿者/ RT (126回)-(2009/09/17(Thu) 23:54:21)

> この辺は設計の問題ですが、私なら取り敢えず簡単に、
> ・IFindTarget インターフェイスと、それを実装する RichTextBoxFinder / WebBrowserFinder を作成
> ・IFindTarget インターフェイスには Find メソッドと Replace メソッドを用意
> ・各 Finder はコンストラクタでコントロールを受け取ってフィールドに保持、Find と Replace を実装
> ・FindDialog クラスのコンストラクタは IFindTarget を受け取りフィールドに保持するようにする
> ・FindDialog のボタンイベントなどに応じて IFindTarget.Find や Replace を呼び出す
> みたいな形にするかな。
> // それともコントロールのインスタンスを Form 外に出すのを気持ち悪がってイベントでやっちゃうかな?

↑の話はちょっと難しくてわからないのですが、↓のコードで、検索する事は出来ました。

private void SearchProc(string SearchKeyWord)
{
if (webBrowser_Base.Document != null)
{
HtmlDocument doc = webBrowser_Base.Document;
mshtml.IHTMLDocument2 doc2 = doc.DomDocument as mshtml.IHTMLDocument2;
mshtml.IHTMLTxtRange textRange = ((mshtml.IHTMLBodyElement)doc2.body).createTextRange();
bool isFound;

textRange = doc2.selection.createRange() as mshtml.IHTMLTxtRange;
if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) //Shift押してたら上方向に検索
{
textRange.moveStart("textedit", -1);
if (textRange.text != null) textRange.moveEnd("character", -1);
else textRange.moveEnd("textedit", 1);
isFound = textRange.findText(SearchKeyWord, -1, 0);
}
else //Shift押してなかったら下方向に検索
{
if (textRange.text != null) textRange.moveStart("character", 1);
textRange.moveEnd("textedit", 1);
isFound = textRange.findText(SearchKeyWord, 1, 0);
}
if (isFound)
{
textRange.scrollIntoView(true);//見つかったらスクロール
textRange.select();//そして範囲選択
}
else
{
MessageBox.Show("「" + SearchKeyWord + "」は見つかりませんでした。");//見つからなかったらメッセージ
}
}
}

置換は、どのようにすれば、出来るでしょうか?SelectedTextのようなプロパティは使えないのでしょうか?
引用返信 編集キー/
■41336 / inTopicNo.6)  Re[3]: ウェブブラウザ上に表示したページのデータを検索・置換
□投稿者/ 魔界の仮面弁士 (1300回)-(2009/09/18(Fri) 00:04:32)
2009/09/18(Fri) 00:05:30 編集(投稿者)
No41333 (RT さん) に返信
> しかし、別のフォームで、webBrowser1のようなコントロール名を使うとエラーが出ます。
実行時エラー(例外)ですか? コンパイルエラーですか?
そのエラーとは、具体的にはどのような内容ですか?

「webBrowser1のような」コントロール名を使うとは、
具体的にはどのようなコードになっているのでしょうか?


> また、findTextの第一引数には、
findText の各引数の意味について。
http://msdn.microsoft.com/en-us/library/aa741525.aspx
http://msdn.microsoft.com/ja-jp/library/cc428095.aspx


> SelectedTextのような、プロパティが、ウェブブラウザにはないようです。
本題からは外れるのですが、そもそもこれらは WebBrowser 自体の機能ではありません。
WebBrowser に表示された HTML に対する DOM の機能です。


WebBrowser に何を表示させるかによって、使用可能な機能も操作方法も異なります。

たとえば、HTML ではなくフォルダを表示させれば、HTML 用の操作手順は使えず、
フォルダ用の操作手順が必要になります。Excel ブックを表示させれば、Excel に対する
操作手順が必要になります。



// フォルダを表示させた場合の操作例

private void Form1_Load(object sender, EventArgs e)
{
    button2.Enabled = false;    
}

private void button1_Click(object sender, EventArgs e)
{
    const int ssfDESKTOP = 0;
    const int ssfSTARTMENU = 11;
    const int ssfWINDOWS = 36;

    object wb = webBrowser1.ActiveXInstance;
    wb.GetType().InvokeMember("Navigate2",
        System.Reflection.BindingFlags.InvokeMethod,
        null, wb, new object[] { ssfDESKTOP });
    button2.Enabled = true;
}

private void button2_Click(object sender, EventArgs e)
{
    MessageBox.Show(webBrowser1.DocumentTitle);
    MessageBox.Show(webBrowser1.Url.ToString());

    object wb = webBrowser1.ActiveXInstance;
    object doc = wb.GetType().InvokeMember("Document",
        System.Reflection.BindingFlags.GetProperty,
        null, wb, new object[0]);

    object folderItem = doc.GetType().InvokeMember("FocusedItem",
        System.Reflection.BindingFlags.GetProperty,
        null, doc, new object[0]);

    if (folderItem == null)
    {
        MessageBox.Show("フォーカス無し");
    }
    else
    {
        object name = folderItem.GetType().InvokeMember("Name",
            System.Reflection.BindingFlags.GetProperty,
            null, folderItem, new object[0]);
        MessageBox.Show(((string)name) + "にフォーカスがあります。");
    }
    
    object folderItems = doc.GetType().InvokeMember("SelectedItems",
        System.Reflection.BindingFlags.InvokeMethod,
        null, doc, new object[0]);
    int count = (int)folderItems.GetType().InvokeMember("Count",
        System.Reflection.BindingFlags.GetProperty,
        null, folderItems, new object[0]);
    MessageBox.Show(count + "個のフォルダ/ファイルが選択されています。");
}

引用返信 編集キー/
■41357 / inTopicNo.7)  Re[5]: ウェブブラウザ上に表示したページのデータを検索・置換
□投稿者/ RT (127回)-(2009/09/18(Fri) 13:16:48)
教えて頂いたpasteHTMLを使って、置換、全て置換の機能を作成する事が出来ました。

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

またよろしくお願いします。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -