はじめに
これまで4回に渡ってQtの基本部分について説明して来ました。今回と次回は、
- ※) Qt 4.
5 Technology Previewの前日にSymbian OSへの移植もアナウンスされています。また、 Nokiaへの買収に伴い、 社名がTrolltechからQt Software, Nokiaに変更されWebページも一新されました。
Qt 4.5 Technology Preview
Technology Previewには、
パフォーマンス改善
Qt 4.
- Graphics View
setViewpor(QGLWidget(QGLFormat(QGL::SampleBuffers))) を呼び出す。 - ウィジェット
QGLWidget(QGLFormat(QGL::SampleBuffers)) を親ウィジェットにする。
描画精度や描画速度を上げようとすると3つの問題があります。
- プラットフォーム固有の描画機能には、
描画上で細かな差異があります。そこで、 プラットフォームに依存せずに正確な描画をしたい場合には、 QImageに描画をしてからQImageを表示するという方法を取ることとなります。しかし、 一般にQImageがクライアントアプリケーション中に存在するデータということから、 プラットフォームによっては描画コストが高くなります。 - OpenGLを描画エンジンにすると速度は改善されますが描画精度が落ちます。正確な描画のためには各プラットフォームの描画エンジンを用いるか、
1)の方法を取ることとなります。 - OpenGLを描画エンジンに使用するには、
僅かな修正ですがすべてのウィジェットのベースクラスを変更しなければなりません。アプリケーション全体で簡単にOpenGLを描画エンジンに切換える方法はありません。
Qt 4.
$ app -graphicssystem raster $ app -graphicssystem opengl
使い方は簡単で、
描画エンジン | Windows | X11 | Mac OS X |
---|---|---|---|
プラットフォームの描画機能 | 60 | 20 | 9 |
ラスター | 60 | 36 | 30 |
OpenGL | 245 | 92 | 215 |
一般に、
Windowsでラスター描画エンジンの効果がないのは、
X11では、
4. | 4. | 4. | 4. | |
---|---|---|---|---|
QPixmap::toImage() | 9286 | 0 | 26685 | 0 |
QPixmap::fromImage() | 9185 | 814 | 31185 | 3450 |
かなりの改善結果です。画像のスケールをスライダで変えて表示するコードを書いて、
描画速度は改善されるのですが、
- ※) Windowsでの2D描画には、
Direct Xも実験的に描画エンジンとして用いられるようになっています。ただし、 ウィジェットが表示されない場合があるなどの問題があります。 - ※) MIT-SHMを使うコードは、
Qt 1から書かれてはいます。
WebKitの改善
第1回で挙げた機能やキャッシュが実装されていて、
その他
ざっと見ただけですが、
- Qt/
Mac OS XのCocoaブランチの取り込み。 - QtTestモジュールへのベンチマーク機能の追加。
- QtXmlPatternsモジュールでのXSL-Tサポート。
- ODF (Open Document Format) のサポート。
- Qt Designerの操作性改善
- Qt/
Mac OS Xでのバンドル作成支援ツールmacdeployの追加。 - リファレンスマニュアルへのQt for Windows CEについての記述の追加。
Qt WebKitの動かし方
Qt WebKitを動かすには3通りの方法があります。
(1) Qt 4.4.3のQt WebKit
現時点での正式リリース版です。Qtにはリリース時のWebKitのソースコードが含まれています。Qt 4.
(2) Qt 4.4.3とオープンソースWebKit
Qt 4.
(3) Qt 4.5 Technology Preview
Qt本体がQt 4.
Qt WebKitのビルド方法
Qt 4.
Qt 4.
1.SVNリポジトリからWebKitを引出します。1Gバイト以上あります。
$ svn checkout http://svn.webkit.org/repository/webkit/trunk WebKit
2.ビルド環境の設定
オプション--releaseまたは--debugを指定してビルドモードを設定し、
$ cd WebKit/WebKitTools/Scripts
$ ./set-webkit-configuration --release
$ export QTDIR <Qt 4.4.3のインストールディレクトリ>
3.ビルド
ビルド方法は以下のようにします。WebKit/
$ cd WebKit/WebKitTools/Scripts $ ./build-webkit
4.実行
最小限のブラウザ機能を実装したWebKit/
$ cd WebKit/WebKitTools/Scripts $ ./run-launcher

Qt WebKitの構成
Qt WebKitは、
クラス | 機能 |
---|---|
QWebFrame | Webページ内のフレーム |
QWebHistory | QWebPageのヒストリー |
QWebHistoryInterface | リンクヒストリーの実装とのインターフェース |
QWebHistoryItem | QWebPageのヒストリー項目 |
QWebHitTestResult | Webページのヒットテスト結果 |
QWebPage | Webドキュメントオブジェクト |
QWebPluginFactory | Webページに組込むプラグイン生成 |
QWebSettings | QWebPageとQWebFrameの設定内容の格納 |
QWebView | Webドキュメントの表示と編集をするウィジェット |
図2に、

Webページの表示
リスト1は、
$ step1 url
QWebViewのインスタンスを生成し、
01: #include <QApplication>
02: #include <QtWebKit>
03:
04: int main( int argc, char** argv )
05: {
06: QApplication app( argc, argv );
07:
08: QUrl url;
09: if ( argc == 1 )
10: url = QUrl( "http://trolltech.com" );
11: else
12: url = QUrl( argv[1] );
13:
14: QWebView* webView = new QWebView( 0 );
15: webView->load( url );
16: webView->show();
17:
18: return app.exec();
19: }

QWebView::load() の実装コードでは、
Qt 4.
12: url = QUrl( argv[1] );
13:
14: QWebSettings* webSettings = QWebSettings::globalSettings();
15: webSettings->setAttribute( QWebSettings::PluginsEnabled, true );
16:
17: QWebView* webView = new QWebView( 0 );
QWebSettingsにはフォントのファミリーやサイズ設定、
Webブラウザらしくする
いくつか機能を追加してWebブラウザらしくすると、

01: #ifndef MAINWINDOW_H
01: #define MAINWINDOW_H
02:
03: #include <QMainWindow>
04: class QWebView;
05: class QLineEdit;
06: class QProgressBar;
07:
08: class MainWindow : public QMainWindow
QMainWindowを用いて、
10: {
11: Q_OBJECT
12:
13: public:
14: MainWindow();
15:
16: protected slots:
17: void changeLocation();
18: void loadFinished();
19: void showLinkHover( const QString& link );
20:
21: private:
22: QWebView* webView;
23: QLineEdit* urlEdit;
24: QProgressBar* progress;
25: };
26:
27: #endif
01: #include <QtWebKit>
02: #include <QWebView>
03: #include <QLineEdit>
04: #include <QProgressBar>
05: #include <QMenuBar>
06: #include <QToolBar>
07: #include <QStatusBar>
08: #include "mainwindow.h"
09:
10: MainWindow::MainWindow()
11: : QMainWindow( 0 )
12: {
13: webView = new QWebView( this ) ;
14: setCentralWidget( webView );
QWebViewのインスタンスを処理の中心となるウィジェットとして設定しています。
15:
16: progress = new QProgressBar( this );
17: progress->setRange( 0, 100 );
18: progress->setMinimumSize( 100, 20 );
19: progress->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
20: progress->hide();
21: statusBar()->addPermanentWidget( progress );
22:
23: connect( webView, SIGNAL( loadProgress( int ) ), progress, SLOT( show() ) );
24: connect( webView, SIGNAL( loadProgress( int ) ), progress, SLOT( setValue( int ) ) );
25: connect( webView, SIGNAL( loadFinished( bool ) ), progress, SLOT( hide() ) );
ステータスバーにロード状況を表示するためにプログレスバーを埋め込みます。この他に、
26:
27: urlEdit = new QLineEdit( this );
28: urlEdit->setSizePolicy( QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy() )
29: connect( urlEdit, SIGNAL( returnPressed() ), SLOT( changeLocation() ) );
URLの入力欄です。横に広がりやすくするようにサイズポリシーを設定し、
30:
31: QToolBar* bar = addToolBar( "Navigation" );
32: bar->setMovable( false );
33: bar->addAction( webView->pageAction( QWebPage::Back ) );
34: bar->addAction( webView->pageAction( QWebPage::Forward ) );
35: bar->addAction( webView->pageAction( QWebPage::Reload ) );
36: bar->addAction( webView->pageAction( QWebPage::Stop ) );
37: bar->addWidget( urlEdit );
ナビゲーションのためのツールバーを作成しています。QActionのインスタンスは、
38:
39: QMenu* fileMenu = menuBar()->addMenu( "&File" );
40: fileMenu->addAction( "Quit", qApp, SLOT( quit() ) );
41:
42: connect( webView, SIGNAL( loadFinished( bool ) ),
43: this, SLOT( loadFinished() ) );
44: connect( webView, SIGNAL( titleChanged( const QString& ) ),
45: this, SLOT( setWindowTitle( const QString& ) ) );
46: connect( webView->page(), SIGNAL( linkHovered( const QString&, const QString&, const QSt& ) ),
47: this, SLOT( showLinkHover( const QString& ) ) );
QWebViewは、
48: }
49:
50: void MainWindow::changeLocation()
51: {
52: QUrl url = urlEdit->text().simplified();
53: urlEdit->setText( url.toString() );
54: webView->load( url );
55: webView->setFocus( Qt::OtherFocusReason );
56: }
URLが入力されてリターンキーが押されると呼出されるスロットです。入力値の頭と末尾の空白を取り除くようにしています。ロード後にQWebViewにフォーカスを設定して、
57:
58: void MainWindow::loadFinished()
59: {
60: urlEdit->setText( webView->url().toString() );
61: }
リンクを辿って表示した場合に、
62:
63: void MainWindow::showLinkHover( const QString& link )
64: {
65: if ( link.isEmpty() )
66: statusBar()->clearMessage();
67: else
68: statusBar()->showMessage( QString( tr( "Open %1" ).arg( link ) ) );
69: }
ポインタがリンクの上にあるときにそのURLをステータスバーに表示し、
01: #include <QApplication>
02: #include <QWebSettings>
03:
04: #include "mainwindow.h"
05:
06: int main( int argc, char** argv )
07: {
08: QApplication app( argc, argv );
09:
10: QWebSettings* webSettings = QWebSettings::globalSettings();
11: webSettings->setAttribute( QWebSettings::PluginsEnabled, true );
12:
13: MainWindow mainWindow;
14: mainWindow.show();
15:
16: return app.exec();
17: }
QMainWindowを継承してカスタマイズしたMainWindowのインスタンスを生成し表示しています。
Webページのレンダリング結果を画像で保存する
GUI機能を用いずQt WebKitの機能のみでWebベースのユーティリティプログラムを作成してみましょう。表3に挙げたQt WebKit関連のクラスの中で、
QWebPageのリファレンスマニュアル に、
$ render url [スケール]
このコマンドを実行すると指定したURLのWebページをレンダリングし、
リスト6が実装コードです。行を追って説明します。
01: #include <QtGui>
02: #include <QtWebKit>
03:
04: class Thumbnailer : public QObject
Webページへのアクセスは、
05: {
06: Q_OBJECT
07:
08: public:
09: Thumbnailer( const QUrl& url, double scale = 1.0 );
10:
11: signals:
12: void finished();
新たに追加したシグナルでWebページをロードし、
13:
14: private slots:
15: void render();
QWebPageでのロードが完了したときに呼び出す処理スロットです。
16:
17: private:
18: QWebPage page;
19: double scale;
20: };
21:
22: Thumbnailer::Thumbnailer( const QUrl& url, double scale )
23: : scale( scale )
24: {
25: page.mainFrame()->load( url );
26: connect( &page, SIGNAL( loadFinished( bool ) ), this, SLOT( render() ) );
Webページpageのメインフレームに指定されたURLを渡してロードしています。レンダリング終了はQWebPageのシグナルloadFinished(bool) でわかるので、
27: }
28:
29: void Thumbnailer::render()
30: {
31: page.setViewportSize( page.mainFrame()->contentsSize() );
QWebPageのビューポート
32:
33: QImage image( page.viewportSize(), QImage::Format_ARGB32 );
ラスターイメージデータQImageをQWebPageのビューポートと同じサイズで用意します。
34:
35: QPainter painter( &image );
36: page.mainFrame()->render( &painter );
37: painter.end();
Qtの2D描画機能を使うには、
38:
39: QImage thumbnail;
40: if ( scale == 1.0 ) {
41: thumbnail = image;
42: } else {
43: QSize size = page.viewportSize() * scale;
44: thumbnail = image.scaled( size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
45: }
46:
47: thumbnail.save( "thumbnail.png" );
48:
49: emit finished();
スケーリングした画像を格納するためにQImageのデータthumbnailを用いています。スケールが1.
50: }
51:
52: int main( int argc, char** argv )
53: {
54: QApplication app( argc, argv );
55:
56: QUrl url = QUrl( "http://trolltech.com" );
57: double scale = 1.0;
58:
59: switch ( argc ) {
60: case 2:
61: url = argv[1];
62: break;
63: case 3:
64: url = argv[1];
65: scale = QString( argv[2] ).toDouble();
66: break;
67: }
68:
69: Thumbnailer thumbnailer( url, scale );
70:
71: QObject::connect( &thumbnailer, SIGNAL( finished() ), &app, SLOT( quit() ) );
コマンドラインで指定したURLのレンダリングが完了したならば、
72:
73: return app.exec();
74: }
75:
76: #include "render.moc"
SVGファイルのレンダリング結果を画像で保存する
Qt Labsには、
- Qt Labs Blogs - WebKit-based SVG rasterizer
- http://
labs. trolltech. com/ blogs/ 2008/ 08/ 06/ webkit-based-svg-rasterizer/
上記ページに書かれている説明から要点のみ説明しましょう。
$ svn2png tiger.svg tiger.png 300 300
コマンドをこのように実行すると300x300の大きさにSVGをレンダリングし、

リスト7とリスト8が上記のコマンドの実装コードです。このコードは、
- svn://
labs. trolltech. com/ svn/ graphics/ dojo/ svg2png
から入手できます。行を追って説明します。
01: #ifndef WEBKIT_SVG_RENDERER
02: #define WEBKIT_SVG_RENDERER
03:
04: #include <QWebView>
05:
06: class WebKitSVGRenderer : public QWebView
07: {
08: Q_OBJECT
09:
10: public:
11: QString fileName;
12: QSize targetSize;
13: WebKitSVGRenderer(QWidget *parent = 0);
14:
15: private slots:
16: void saveResult(bool ok);
17: };
18:
19: #endif // WEBKIT_SVG_RENDERER
20:
11: WebKitSVGRenderer::WebKitSVGRenderer(QWidget *parent) : QWebView(parent)
12: {
13: connect(this, SIGNAL(loadFinished(bool)), this, SLOT(saveResult(bool)));
先に説明したサンプルと同様に、
21: #define EVAL_JS(x) page()->mainFrame()->evaluateJavaScript((x))
Qt 4.
23: void WebKitSVGRenderer::saveResult(bool ok)
24: {
25: // crude error-checking
26: if (!ok) {
27: std::cerr << "Failed loading " << qPrintable(url().toString()) << std::endl;
28: QApplication::instance()->exit(1);
29: return;
ちょっとわかり難いコードかもしれません。QApplication::exec() で開始されたイベントループを終了コードを指定して抜けるようにしています。イベントループを実際に抜けるのは、
32: // ensure it is an SVG
33: QString root = EVAL_JS("document.rootElement.nodeName").toString();
34: if (root.isEmpty() || root.compare("svg", Qt::CaseInsensitive)) {
35: std::cerr << "Not an SVG! " << qPrintable(url().toString()) << std::endl;
36: close();
37: return;
38: }
JavaScriptでドキュメントのノード名を取出し、
40: // get the dimension, i.e. the width and height attributes
41: // Note: if an attribute is not defined WebKit would return the view's dimension
42: // hence the hack of checking for the MAGIC_SIZE
43: double ww = EVAL_JS("document.rootElement.width.baseVal.value").toDouble();
44: double hh = EVAL_JS("document.rootElement.height.baseVal.value").toDouble();
45: if (ww == 0.0 || hh == 0.0 || ww == MAGIC_SIZE || hh == MAGIC_SIZE) {
46: std::cerr << "SVG does not specify proper width and height! " << std::endl;
47: close();
48: return;
49: }
こちらも同様にしてJavaScriptを使って、
このサンプルの説明があるWebページから入手できるSVGファイルは、
59: // create the target surface
60: QSize t = targetSize.isValid() ? targetSize : QSize(ww, hh);
61: QImage img(t, QImage::Format_ARGB32_Premultiplied);
62: img.fill(Qt::transparent);
63:
64: // prepare the painter
65: QPainter p(&img);
66: qreal xs = targetSize.isValid() ? targetSize.width() / ww : 1.0;
67: qreal ys = targetSize.isValid() ? targetSize.height() / hh : 1.0;
68: p.scale(xs, ys);
69:
70: // the best quality
71: p.setRenderHint(QPainter::Antialiasing);
72: p.setRenderHint(QPainter::TextAntialiasing);
73: p.setRenderHint(QPainter::SmoothPixmapTransform);
先に説明したサンプルとの描画方法と違い、
75: page()->mainFrame()->render(&p);
76: p.end();
77:
78: if (img.save(fileName, "png"))
79: std::cout << "Result saved to " << qPrintable(fileName) << std::endl;
80: else
81: std::cout << "Failed to save to " << qPrintable(fileName) << std::endl;
82:
83: close();
84: }
SVGを変換しつつ描画をしてから、
SVGのレンダリングをしているWebKitSVGRenderでは、
まとめと次回の予告
今回は、
次回は、