Return to Linux Life Edit

  ホーム · 全てのクラス · 主要なクラス · 注釈付きクラス一覧 · グループ別クラス · 関数一覧

[前へ: Interview フレームワーク] [ホーム] [次へ: Scribeクラス]

Arthur 描画機構

この文書では、Qt がグラフィックスを描画するときに Qt3 で使うアプローチと Qt4 で使うアプローチとで比較しながら、Qt4 での描画システムを説明していきます。

アーキテクチャ

Qt4 の描画システムは主に QPainterと、 QPaintDevice QPaintEngineクラスを基点にしています。 QPainter は、例えば drawLine() や drawRect() と言った、描画操作を実行するのに使われるクラスです。 QPaintDevice は、 QPainterで描画可能なデバイスをあらわします。 QWidget QPixmap はどちらも QPaintDevices です。 QPaintEngine は異なるタイプのデバイスに描画するときに使われるインターフェースを提供します。

Qt3 ではどうだったのか

Qt3 では QPainter はウィジェットとピクスマップに描画できました。(Windows と Mac OS X ではまたプリンタに対しても描画できました)。他にサポートしたいデバイスがある場合、例えば QPrinter on X11には、 QPaintDevice を継承し、仮想関数 QPainter::cmd() を実装しました。こうして実装されたデバイスは外部デバイスとして扱われました。

QPainter は外部デバイスを認識し、それぞれの描画操作をシリアライズして実装した cmd() 関数に渡すことができました。こうして外部のデバイスを実装することはできましたが、Qt4 にあたっていくつかの短所もありました。そのうちひとつが、外部デバイスは QPainter で実装されている関数を再利用できないことです。なぜなら QPainter はプラットフォームのウィジェット/ピクスマップに依存していたからです。複数のデバイスバックエンド、例えば OpenGL をサポートすることは不便でそれほど効率的なものとはなりませんでした。

このことから、Qt4 ではより便利で直観的な API を提供しようと考えたのです。

Qt4 ではどのように描画が行われるか

Qt 4 では QPaintEngine という抽象クラスが設けられている. 特定のデバイスタイプへ描画する際に必要となる具体的な機能はこのクラスの実装が提供する. QPaintEngine クラスは QPainter QPaintDeviceだけで内部的に利用され、 QPaintEngine をサブクラス化して新しいデバイスタイプを再実装するのでもない限り、アプリケーションプログラマからは隠匿されている. 現在 Qt では、以下のプラットフォームとAPIに対する描画エンジンが用意されている:

新しいバックエンドをサポートするには QPaintEngine を派生させ、その仮想関数を再実装しなければならない. また、 QPaintDevice から派生させ、仮想関数 QPaintDevice::paintEngine() を再実装してやる必要がある. このことによって、 QPainter へそのデバイスへ描画するのに用いる描画エンジンを知らせる。

このアプローチの主たる利点としては、全ての描画が同一の描画パイプライン上で行われるという部分にある. これにより新機能を追加しやすく、また、未サポートのデバイスに対しても標準的な実装を用意しやすくなると期待される.

Qt 4 の描画システムにおける新機能

グラデーションブラシ

Qt 4 では、グラデーションブラシを使って形を塗りつぶすことができる. グラデーションは、与えられた一点の色から、別の地点にある別の色への推移として描かれる. グラデーションは、ある色から別の色へ、あるいは、グラデーション領域内において選択した複数地点の色を渡りあるくように描くことができる. Qt 4 では線状、放射状、および円錐状のグラデーションがサポートされる.

線状のグラデーションでは、2つの特徴点を用いて描画する. 線状のグラデーションブラシを使うには QLinearGradient オブジェクトを生成し、それをブラシとして設定すればよい.

    QLinearGradient gradient(0, 0, 100, 100);
    gradient.setColorAt(0, Qt::red);
    gradient.setColorAt(0.5, Qt::green);
    gradient.setColorAt(1, Qt::blue);
    painter.setBrush(gradient);
    painter.drawRect(0, 0, 100, 100);

上記のコードによって、次のピクスマップで示すようなパターンが生成される:

放射状のグラデーションは、中心、半径、および焦点を指定しておこなう. 放射状ブラシを使うには QRadialGradient オブジェクトを生成し、それをブラシとして設定すればよい.

    QRadialGradient gradient(50, 50, 50, 30, 30);
    gradient.setColorAt(0.2, Qt::white);
    gradient.setColorAt(0.8, Qt::green);
    gradient.setColorAt(1, Qt::black);
    painter.setBrush(gradient);
    painter.drawEllipse(0, 0, 100, 100);

上記のコードにより次のピクスマップで示すようなパターンが生成される:

円錐状グラデーションは、中心および開始角を指定しておこなう. 円錐状ブラシを使うには QConicalGradient オブジェクトを生成し、それをブラシとして設定すればよい.

    QConicalGradient gradient(60, 40, 0);
    gradient.setColorAt(0, Qt::black);
    gradient.setColorAt(0.4, Qt::green);
    gradient.setColorAt(0.6, Qt::white);
    gradient.setColorAt(1, Qt::black);
    painter.setBrush(gradient);
    painter.drawEllipse(0, 0, 100, 100);

上記のコードにより次のピクスマップで示すようなパターンが生成される:

アルファブレンディングDrawing

Qt 4 では、アルファブレンディング付きのアウトライン描画と塗りつぶしができる. 色のアルファチャネルは QColorを使って指定する.

// 半透過の赤色を指定<BR>painter.setBrush(QColor(255, 0, 0, 127));<BR>painter.drawRect(0, 0, width()/2, height());<BR><BR>// 半透過の青色を指定<BR>painter.setBrush(QColor(0, 0, 255, 127));<BR>painter.drawRect(0, 0, width(), height()/2);

上記のコードにより以下の出力が得られる:

アルファブレンディング対応の描画は、Windows と Max OS X、および X Render エクステンションのインストールされた X11 にて利用できる.

QPainter と QGLWidget

QPainter QGLWidget 上でも QWidgetと同様に、開くことができるようになった.これにより、ほとんどの描画操作において OpenGL の高いパフォーマンスが活用できるようになると思われる.

アンチエイリアス

プラットフォームにネイティブで用意されている描画 API がアンチエイリアスの機能をサポートしている場合、オプションによって基本グラフィックの描画時にエッジのアンチエイリアスを有効にできるようにした.

    // One line without anti-aliasing
    painter.drawLine(0, 0, width()/2, height());
    // One line with anti-aliasing
    painter.setRenderHints(QPainter::Antialiasing);
    painter.drawLine(width()/2, 0, width()/2, height());

これにより以下の出力が得られる:

アンチエイリアスは QImage への描画および、XRender の無い X11 を除いた全てのシステムにおいてサポートされる.

ネイティブグラフィック操作の積極的な利用

Qt 4 の描画システムにおいて、ネイティブグラフィック操作を積極的に利用することにした. これらはハードウェア上で実行した際にパフォーマンスが出やすく、ソフトウェアのみによる実装よりも速度面で遥かに優位であるといえる.

ネイティブの変形操作 (Max OS X と OpenGL で利用できる) が用意されている場合には、ワールドマトリックスを使った描画がとても高速におこなえる. ピクスマップ操作では、ハードウェアでの実装とほとんど変わらない性能が出ることもある.

ペインター パス

ペインター パスは矩形、楕円形、直線、曲線といった複数のグラフィカルなブロックからなるオブジェクトである. ペインターパスは塗りつぶしたり、輪郭を抽出したり、その一部を切り取って利用したりすることができる. ペインターパスを使うことにより、通常の描画操作の範疇で曲線を含んだ図形を構築・描画することが可能となる.

ブロックは矩形や楕円といった閉曲線のかたちで連結されるか、または独立した開曲線のかたちをとる. 開曲線である場合、図形内部の塗りつぶしは行われない.

以下のコード例は、パスの使い方について示したものである. この例での painter は、太さが3であるライトブルー色のペンを持っていることにする. まず最初に矩形を追加する.この結果、全体としては閉曲線の図形となる. 次いでベジェ曲線を追加し、最後にパスを描画している.

    QPainterPath path;
    path.addRect(20, 20, 60, 60);
    path.addBezier(0, 0,  99, 0,  50, 50,  99, 99);
    path.addBezier(99, 99,  0, 99,  50, 50,  0, 0);
    painter.drawPath(path);

上記のコードからは以下の出力が得られる:

ウィジェットのダブルバッファリング

Qt 4 では、全てのウィジェットはデフォルトでダブルバッファリングされる.

以前のバージョンの Qt では、ダブルバッファリングはオフスクリーンのピクスマップに描画し、それをスクリーンにコピーすることで実現していた. 例:

    QPixmap buffer(size());
    QPainter painter(&buffer);
    // Paint code here
    painter.end();
    bitBlt(this, 0, 0, &buffer);

ダブルバッファリングが QWidget の内部で処理されるようになったので、今後は以下のようになる:

    QPainter painter(this);
    // Paint code here
    painter.end();

ダブルバッファリングはデフォルトで有効になっているが、ウィジェットのアトリビュート Qt::WA_PaintOnScreenの設定により、個々に無効化することができる.

    unbufferedWidget->setAttribute(Qt::WA_PaintOnScreen);

ペンとブラシの変形

Qt 3 では、ペンとブラシがペインタの変形マトリックスの影響を受けることはなかった. たとえば拡大・縮小されたペインタを使って、幅が1のペンで矩形を書いたような場合、線幅は1のままであった.この仕様は、拡大や高精細描画のような機能の実装を難しくしていた.

Qt 4 では、ペンとブラシはペインタの変形マトリックスに従うようになった.

ただし、この機能は目下開発中であり、全てのプラットフォームにおいてサポートされているわけではない点に留意されたい.

カスタムフィル ペン

Qt 4 では、アウトラインをどのように塗りつぶすかを指定することができる. 単色または QBrushを選択でき、テキストとアウトラインのいずれに対しても、また、テクスチャとグラデーションフィルのいずれによっても、塗りつぶしをおこなうことができる.

    QLinearGradient gradient(0, 0, 100, 100);
    gradient.setColorAt(0, Qt::blue);
    gradient.setColorAt(1, Qt::red);
    painter.setPen(QPen(gradient, 0));
    for (int y=fontSize; y<100; y+=fontSize)
        drawText(0, y, text);

上記のコードによって以下の出力が得られる:

描画デバイスとしての QImage

以前のバージョンと比較した際の、 Qt 4 における最大の改良箇所としては、ピクセルベースのラスタ描画エンジンが導入され、利用者が QImage上でペインタを開けるようにしている点である. QImage 描画エンジンでは、 QPainter の全機能 (パス, アンチエイリアシング, アルファブレンディング, その他) を使うことができ、全てのプラットフォーム上で利用可能となっている.

この利点の一つとしては、いかなる描画操作をおこなっても、その結果に関するピクセル単位での厳密性をプラットフォームに依存することなく保証できるところである.

イメージへの描画は、他のペイントデバイスに描画するのと同様である.

    QImage image(100, 100, 32);
    QPainter painter(&image);
    // painter commands.
    painter.end();

[前へ: Interview フレームワーク] [ホーム] [次へ: Scribe クラス]


Copyright © 2005 Trolltech Trademarks
Qt 4.0.0