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

[前へ: 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, this was done by deriving from 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);

The code shown above produces a pattern as shown in the following pixmap:

Conical gradients are specified using a center and a start angle. Setting a conical brush is done by creating a 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);

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

Alpha-Blended Drawing

With Qt 4 we support alpha-blended outlining and filling. The alpha channel of a color is defined through QColor. The alpha channel specifies the transparency effect, 0 represents a fully transparent color, while 255 represents a fully opaque color. For example:

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

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

Alpha-blended drawing is supported on Windows, Mac OS X, and on X11 systems that have the X Render extension installed.

QPainter and QGLWidget

It is now possible to open a QPainter on a QGLWidget as if it were a normal QWidget. One huge benefit from this is that we utilize the high performance of OpenGL for most drawing operations, such as transformations and pixmap drawing.

Anti-Aliased Edges

On platforms where this is supported by the native drawing API, we provide the option of turning on anti-aliased edges when drawing graphics primitives.

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

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

Anti-aliasing is supported when drawing to a QImage and on all systems, except on X11 when XRender is not present.

Extensive Use of Native Graphics Operations

Where this makes sense, Qt uses native graphics operations. The benefit we gain from this is that these operations can potentially be performed in hardware, giving significant speed improvements over many pure-software implementations.

Among these are native transformations (Mac OS X and OpenGL), making painting with a world matrix much faster. Some pixmap operations have also been moved closer to the underlying hardware implementations.

Painter Paths

A painter path is an object composed of a number of graphical building blocks, such as rectangles, ellipses, lines, and curves. A painter path can be used for filling, outlining, and for clipping. The main advantage of painter paths over normal drawing operations is that it is possible to build up non-linear shapes which can be drawn later in one go.

Building blocks can be joined in closed subpaths, such as a rectangle or an ellipse, or they can exist independently as unclosed subpaths, although an unclosed path will not be filled.

Below is a code example on how a path can be used. The painter in this case has a pen width of 3 and a light blue brush. We first add a rectangle, which becomes a closed subpath. We then add two bezier curves, and finally draw the entire path.

 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);

The code above produces the following output:

Widget Double-Buffering

In Qt 4, all widgets are double-buffered by default.

In previous versions of Qt double-buffering was achieved by painting to an off-screen pixmap then copying the pixmap to the screen. For example:

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

Since the double-buffering is handled by QWidget internally this now becomes:

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

Double-buffering is turned on by default, but can be turned off for individual widgets by setting the widget attribute Qt::WA_PaintOnScreen.

 unbufferedWidget->setAttribute(Qt::WA_PaintOnScreen);

Pen and Brush Transformation

In Qt 3, pens and brushes weren't affected by the painter's transformation matrix. For example, if you drew a rectangle with a pen width of 1 using a scaled painter, the resulting line width would still be 1. This made it difficult to implement features such as zooming and high-resolution printing.

In Qt 4, pens and brushes honor the painter's transformation matrix.

Note that this feature is still in development and not yet supported on all platforms.

Custom Filled Pens

In Qt 4, it is possible to specify how an outline should be filled. It can be a solid color or a QBrush, which makes it possible to specify both texture and gradient fills for both text and outlines.

 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 as a Paint Device

A great improvement of Qt 4 over previous versions it that it now provides a pixel-based raster paint engine which allows users to open a painter on a QImage. The QImage paint engine supports the full feature set of QPainter (paths, antialiasing, alphablending, etc.) and can be used on all platforms.

One advantage of this is that it is possible to guarantee the pixel exactness of any drawing operation in a platform-independent way.

Painting on an image is as simple as drawing on any other paint device.

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

SVG Rendering Support

Scalable Vector Graphics (SVG) is an language for describing both static and animated two-dimensional vector graphics. Qt includes support for the static features of SVG 1.2 Tiny, taking advantage of the improved paint system in Qt 4. SVG drawings can be rendered onto any QPaintDevice subclass, such as QWidget, QImage, and QGLWidget, to take advantage of specific advantages of each device. This approach gives developers the flexibility to experiment, in order to find the best solution for each application.

Since SVG is an XML-based format, the QtXml module is required to read SVG files. For this reason, classes for SVG handling are provided separately in the QtSvg module.

Displaying an SVG drawing in an application is as simple as displaying a bitmap image. QSvgWidget is a display widget that can be placed in an appropriate place in a user interface, and new content can be loaded as required. For example, a predetermined file can be loaded and displayed in a widget with little effort:

     QSvgWidget window(":/files/spheres.svg");
     window.show();

For applications with more specialized requirements, the QSvgRenderer class provides more control over the way SVG drawings are rendered and animated.

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


Copyright © 2007 Trolltech Trademarks
Qt 4.3.3