2012年07月28日

Trident/WebKit/Geckoで簡素なWebブラウザを作る(C#)

前回までの記事でTrident(IEコンポーネントのWebBrowserコントロール)、WebKit(WebKit.NET)、Gecko(GeckoFX)でブラウザを作って見たので、この三つの並べて表示の比較が行える“マルチレンダリングブラウザ”を作ってみます。

基本的には前回までの記事で作成したプログラムをちょっと改造するような感じになります。

  • WebBrowser、WebKitBrowser、GeckoWebBrowserコントロールを並べて配置する。今回はフォームのリサイズに対応するため、TableLayoutPanelと組み合わせて自動調整させる
  • 「進む」「戻る」などのボタン押下時のアクションは、3つのコントロールを同時に動かす
  • リンクをクリックしてページを移動する場合、他のコントロールも移動させる
  • ページのタイトルは代表としてWebBrowserのものを使う。他のコントロールではイベント処理しない

実際に作ってみたのはこんな感じです。

public Form1()
{
    InitializeComponent();

    this.comboBox1.Text = "http://www.google.com";
    this.button1.Text = "戻る";
    this.button2.Text = "進む";
    this.button3.Text = "更新";
    this.button4.Text = "ホーム";
    this.button5.Text = "移動";
}

/// <summary>
/// URL入力エリア:選択変更
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    try
    {
        // 移動
        webBrowser1.Navigate(comboBox1.Text);
        webKitBrowser1.Navigate(comboBox1.Text);
        geckoWebBrowser1.Navigate(comboBox1.Text);
    }
    catch (Exception exc)
    {
        MessageBox.Show(exc.Message, exc.Source);
    }
}

/// <summary>
/// URL入力エリア:キー入力
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
    // エンターキー
    if (e.KeyCode == Keys.Enter)
    {
        // 移動ボタン入力と同じ
        button5.PerformClick();
    } 
}

/// <summary>
/// 戻るボタン
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
    // 戻る
    this.webBrowser1.GoBack();
    this.webKitBrowser1.GoBack();
    this.geckoWebBrowser1.GoBack();
}

/// <summary>
/// 進むボタン
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
    // 進む
    this.webBrowser1.GoForward();
    this.webKitBrowser1.GoForward();
    this.geckoWebBrowser1.GoForward();
}

/// <summary>
/// 更新ボタン
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
    // 更新(再読み込み)
    this.webBrowser1.Refresh();
    this.webKitBrowser1.Reload();
    this.geckoWebBrowser1.Reload();
}

/// <summary>
/// ホームボタン
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
    // ホームへ移動
    this.webBrowser1.GoHome();
}

/// <summary>
/// 移動ボタン
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{
    // 入力したURLに移動する
    try
    {
        string url = this.comboBox1.Text;
        // "http://"が無ければ補完
        if (this.comboBox1.Text.StartsWith("http://") == false)
        {
            url = "http://" + url;
        }
        // 移動
        this.webBrowser1.Navigate(url);
        this.webKitBrowser1.Navigate(url);
        this.geckoWebBrowser1.Navigate(url);
        this.comboBox1.Items.Add(url);
    }
    catch(Exception exc)
    {
        MessageBox.Show(exc.Message, exc.Source);
    }
}

/// <summary>
/// Webブラウザ:ナビゲーション実行時
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
    if (this.webBrowser1.Url == null) return;

    if (this.comboBox1.Text != this.webBrowser1.Url.ToString())
    {
        try
        {
            // URL入力エリアにナビゲートしたサイトのURLを設定
            this.comboBox1.Text = webBrowser1.Url.ToString();

            // 他のWebBrowserを連動させる
            this.webKitBrowser1.Navigate(this.comboBox1.Text);
            this.geckoWebBrowser1.Navigate(this.comboBox1.Text);
        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message, exc.Source);
        }
    }

    // フォームのタイトルをナビゲートしたサイトのタイトルを設定
    this.Text = webBrowser1.Document.Title.ToString();
}

/// <summary>
/// WebKitブラウザ:ナビゲーション実行時
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void webKitBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
    if (this.webKitBrowser1.Url == null) return;

    if (this.comboBox1.Text != this.webKitBrowser1.Url.ToString())
    {
        try
        {
            // URL入力エリアにナビゲートしたサイトのURLを設定
            this.comboBox1.Text = this.webKitBrowser1.Url.ToString();

            // 他のWebBrowserを連動させる
            this.webBrowser1.Navigate(this.comboBox1.Text);
            this.geckoWebBrowser1.Navigate(this.comboBox1.Text);
        }
        catch(Exception exc)
        {
            MessageBox.Show(exc.Message, exc.Source);
        }
    }
}

/// <summary>
/// GeckoWebKitブラウザ:ナビゲーション実行時
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void geckoWebBrowser1_Navigated(object sender, Skybound.Gecko.GeckoNavigatedEventArgs e)
{
    if (this.geckoWebBrowser1.Url == null) return;

    if (this.comboBox1.Text != this.geckoWebBrowser1.Url.ToString())
    {
        try
        {
            // URL入力エリアにナビゲートしたサイトのURLを設定
            this.comboBox1.Text = this.geckoWebBrowser1.Url.ToString();

            // 他のWebBrowserを連動させる
            this.webBrowser1.Navigate(this.comboBox1.Text);
            this.webKitBrowser1.Navigate(this.comboBox1.Text);
        }
        catch(Exception exc)
        {
            MessageBox.Show(exc.Message, exc.Source);
        }
    }
}

/// <summary>
/// Webブラウザ:新しいウィンドウが開かれたとき
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void webBrowser1_NewWindow(object sender, CancelEventArgs e)
{
    // キャンセル
    e.Cancel = true;

    // ここではキャンセルしているので新しいウィンドウは開かないし画面遷移もしない
    // 新しいウィンドウを開かずに内部のブラウザで開くためにはwebBrowserの改造が必要。
    // 今回は省略
    // [参照]
    // http://agrimo.jp/wp/?page_id=1059
    // http://vsug.jp/tabid/63/forumid/45/threadid/9273/scope/posts/Default.aspx
}

実行結果はこんな感じです。
MultiBrowser-Sample-01.png
MultiBrowser-Sample-02.png

とりあえずは簡素なブラウザと言うことで妥協していますが、ちゃんとしたブラウザとして使用するためにはまだまだ課題が残っています。

  • 『ホームへ移動』ボタンのWebKit,Geckoへの対応
  • 『新しいウィンドウで開く』への対応
  • Googleの検索窓のような動的に変化するページの対応
  • 読み込み中を表すプログレスバーやメッセージの表示
  • ときどきエラーが出る(特定のサイトをGeckoで見ると死ぬ?)
  • スクロールバーの連動
  • 実行ファイル配布の方法(WebKitやXULRunnerのDLL群を一緒に配布しなければいけない)
などなど……。
気が向いたら改造するかもしれませんが、まあこのまま放置かな……?

いつも思うんですが、C#とか.NETでは、何かやろうとしたときに何でも簡単にできるくせに、本気で何かやろうとしたときは凄く大変。今回のも“簡易ブラウザ”とか言ってますが、このレベルならちょっとコンポーネントをインストールしてちょろちょろっとコードを書けば、誰でも作れちゃうけど、そこから先、本格的なブラウザに仕立て上げるには、色々調べなきゃいけないし、まぁ大変です。
自分でちょっと使うツールとか作るには良いんですけどね……。

良かったらクリックしてください
にほんブログ村 IT技術ブログ プログラム・プログラマーへ  人気ブログランキングへ

posted by among at 19:04 | Comment(5) | TrackBack(0) | C#
この記事へのコメント
初めましてあべと申します。Gecko周りで参考にさせていただいています。
さてドキュメントのタイトルをフォームに反映するところですが、Navigatedでは読み込みが開始された時点でイベントが起きてしまいますので、ドキュメントのタイトルが読み込めていない場合があるように思えます。DocumentCompletedでドキュメントのタイトルを取得する方が良くないですか?
Posted by あべ at 2013年05月20日 16:16
漢方店コム:効果のあるダイエットサプリ、
漢方ダイエットグッズを直送!
ダイエット個人輸入代行 http://kanpoten.com

効果のあるダイエット kanpoten.com
漢方ダイエット kanpoten.com
ダイエットグッズ kanpoten.com

V26激痩せダイエット薬 http://kanpoten.com/products/detail30.html
曲美 http://kanpoten.com/products/detail5.html
集中ダイエットカプセル http://kanpoten.com/products/detail34.html
Posted by ダイエット薬 at 2013年12月12日 18:29
http://kanpoten.com/products/detail5.html 曲美 3,880 円
http://kannpou.org ダイエット漢方薬
http://www.bathmsc.net 漢方ダイエットサプリ検証
http://kannpou.org/products/detail51.html  睡眠 サプリ
http://www.cqmrmfsh.com 産後ダイエット方法
http://kanpoten.com/products/detail40.html 終極痩身カプセル 1,270 円
Posted by ダイエット 薬 at 2014年02月28日 12:31
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/57163117

この記事へのトラックバック