QPainter: Qt グラフィックス レンダリング エンジン
Qt は、豊富で強力な描画機能を備えたクロスプラットフォームの C++ アプリケーション フレームワークです。Qt では、グラフィックスやテキストの描画に使用される主なクラスは QPainter です。QPainter は、線、多角形、画像、テキストなどを描画できるスキャンラインベースのグラフィック レンダリング エンジンです。
この章では、描画に QPainter クラスを使用する方法を学びます。その前に、次のことを理解しておく必要があります。
- C++ の基本構文とオブジェクト指向プログラミング
- Qtの基本コンポーネントとAPI
- Qt シグナル合計メカニズム
QPainterクラスの概要
QPainter は Qt のコア描画クラスの 1 つで、さまざまなグラフィックやテキストを描画するためのさまざまなメソッドを提供します。QPainter クラスは、デバイス固有の QPainterDevice オブジェクトと対話することによって、ウィンドウ上に 2 次元グラフィックスをレンダリングします。
QPainter は QWidget や、QImage や QPrinter などの他の表示デバイスとともに使用できるため、複雑なジオメトリやテキストを画面上に簡単にレンダリングできます。
QPainter の効率は、特に初心者にとって混乱を招く可能性がありますが、QPainter は実際には、ほとんどのタイプのグラフィックスとテキスト データを迅速にレンダリングする最適化されたアルゴリズムを使用しています。さらに、QPainter はダブルバッファリングテクノロジーも実装しています。
QPainter は、次の操作を簡単に実装するための豊富な API も提供します。
- 線分、多角形、楕円などの基本的な幾何学的形状を描画します。
- 長方形、多角形、複雑なパスを塗りつぶします。
- 必要に応じてテキストを描画し、レイアウトします。
- 画像とピクセルデータを描画します。
- 描画オブジェクトを変形および移動します。
QPainter の使い方を学び始めましょう!
Qペインター塗装設備
QPainterは、さまざまなQPainterDeviceクラス(ウィンドウ、ピックスマップ、プリンターなど)と対話し、QPainterDeviceおよびQPaintDeviceMetricsのbegin()およびend()メソッドを通じてペイントデバイスを制御します。
次のコード スニペットでは、QImage (画像) が生成され、QPainterDevice として使用されるときに、QPainter を使用して画像が描画されることがわかります。
QImage image(400, 400, QImage::Format_RGB32);
QPainter painter(&image); // 创建一个绘制器并将它与 Image 关联起来
painter.fillRect(image.rect(), Qt::white); // 填充矩形背景为白色
QPen pen(Qt::green, 4, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
painter.drawLine(50, 250, 200, 100); // 绘制直线
painter.drawRect(150, 150, 50, 50); // 绘制矩形
painter.drawEllipse(250, 50, 100, 150); // 绘制椭圆
painter.end(); // 和上面一样,必须要调用 end() 结束绘画
QImage を QPainterDevice として使用すると、オフスクリーン レンダリングが可能になり、ウィンドウやプリンターの外側に描画してファイルに保存できるようになります。QImage をファイルに書き込む例を次に示します。
image.save("example.jpg", "JPG");
QImage に加えて、QWidget (または派生クラス) を QPainterDevice として使用することもできます。その場合、QPainter は自動的にウィンドウ上に描画します。QWidget でコンテンツをペイントする前に、まず QWidget で QPainter を選択する必要があることに注意してください。
QWidget を QPainterDevice として使用するサンプルコード:
void MyWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.fillRect(rect(), Qt::white);
QPen pen(Qt::blue, 3);
painter.setPen(pen);
painter.drawLine(0, 0,(), height());
painter.drawLine(width(), 0, 0, height());
}
幾何学模様を描く
QPainter は、線、長方形、円、楕円などの基本的な幾何学的形状を描画するためのさまざまな方法を提供します。QPainter を使用する場合、最初にグラフィックス プロパティ、ブラシ、色を設定する必要があります。
ペンとブラシ
幾何学的形状ごとに独自の色とブラシを設定できますが、多くの場合、これらのプロパティは QPainter で描画されるすべての幾何学的形状に適用されます。QPainter は、QPen クラスと QBrush クラスを使用してこれらのプロパティを管理します。
QPen はストロークを定義します。色、幅、スタイル、線の終点、角のタイプを定義できます。QPen オブジェクトを作成するときは、色と線の幅を指定する必要があります。また、さまざまなプロパティを設定することで他のオプションも調整できます。
QBrush は、色、グラデーション、テクスチャなどを定義できるパターンまたは色の塗りつぶしを定義します。QBrush オブジェクトを作成するときは、それに QColor オブジェクトを渡すことも (色で塗りつぶしたい場合)、QGradient (QLinearGradient や QRadialGradient など) を使用してグラデーション効果を作成することもできます。
それでは、幾何学的図形を描く方法を見てみましょう。三角形と台形の描画例を次に示します。
void MyWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QLinearGradient gradient(0, 0, width(), height());
// 渐变色填充
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(0.5, Qt::green);
gradient.setColorAt(1, Qt::blue);
QBrush brush(gradient); // 带有渐变色的画刷
painter.setBrush(brush); // 设置画刷
painter.setPen(Qt::black); // 设置铅笔颜色
// 绘制三角形
QPolygonF triangle;
triangle << QPointF(0, 0) << QPointF(width(), 0) << QPointF(0, height());
painter.drawPolygon(triangle);
// 绘制梯形
QPolygonF trapezoid;
trapezoid << QPointF(0, 0) << QPointF(width(), 0) << QPointF(width() - 50, height()) << QPointF(50, height());
painter.drawPolygon(trapezoid);
}
上の例では、QPolygonF を使用して三角形と台形の頂点を定義します。次に、それを QPainter のdrawPolygon 関数に渡して描画します。
QPolygonF オブジェクトを定義するときは、すべての点の座標を指定する必要があることに注意してください。これらの座標はローカル座標系を参照します。
長方形と円
QPainter は、長方形や円など、他の一般的なグラフィックを描画するためのメソッドも提供します。以下は、QPen と QBrush を使用して、それぞれ長方形と円の外観を設定する簡単な例です。
void MyWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPen pen(Qt::black, 2, Qt::SolidLine); // 定义铅笔
painter.setPen(pen); // 设置铅笔
Q::blue, Qt::Dense4Pattern);// 定义画刷
painter.setBrush(brush); // 设置画刷
// 绘制矩形
QRectF rect(10, 10, 100, 50); // 定义矩形区域
painter.drawRect(rect); // 绘制矩形
// 绘制圆
QRectF circle(150, 10, 50, 50); // 定义圆形的外接矩形
painter.drawEllipse(circle); // 绘制圆形
}
上の例では、QRectF を使用して四角形と円の位置とサイズを指定します。また、QPen、QBrush、および QRectF オブジェクトをパラメーターとして QPainter クラスの描画関数に渡します。
テキストを描画する
QPainter はテキストを描画する方法も提供します。これを行うには、drawText 関数を使用します。文字列と、文字列の下部の水平方向および垂直方向の配置の座標を指定する必要があります。より詳細な制御が必要な場合は、drawStaticText を使用できます。
次のコードは、ウィンドウにテキストを描画する方法を示しています。
void MyWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QFont font;
font.setPointSize(24);
font.setBold(true);
painter.setFont(font);
QString text = "Hello, world!";
QRect rect = painter.boundingRect(0, 0, width(), height(), Qt::AlignCenter, text);
painter.drawText(rect, text, Qt::AlignCenter);
}
上記のコードでは、まず QFont オブジェクトを作成してフォントのサイズと太さを設定します。次に、文字列を作成し、それが引き起こす四角形オブジェクトを取得します。最後に、QRect パラメーターと QString パラメーターを指定してdrawText 関数を呼び出し、ウィンドウに文字列を表示します。
配置を指定しない場合、テキストは Painter で指定された四角形の左上隅に配置されます。
パフォーマンス
QPainter は、任意の形状、テキスト、画像をレンダリングするために使用できる強力な描画ツールです。その柔軟性と高度に最適化されたアルゴリズムにより、リアルタイム グラフィックスの描画にも広く使用されています。
ただし、複雑なジオメトリを描画したり、多数のテクスチャやメッシュを使用したりすると描画パフォーマンスに影響を与える可能性があるため、場合によっては QPainter が最適な選択ではない場合があります。この場合、OpenGL や Vulkan などの特殊なグラフィック ライブラリを使用する必要がある場合があります。
さらに、パフォーマンスを向上させるために、QPainter を使用するときは次のガイドラインに従うことをお勧めします。
- PaintEvent 関数が呼び出されるたびに QPen および QBrush オブジェクトを再作成することは避けてください。可能な限り、以前に作成したオブジェクトを再利用します。
- ウィンドウに単純なグラフィックを描画する場合は、QImage の代わりに QPixmap を使用します。通常、QPixmap は QImage よりも効率的に画面にレンダリングされるためです。
- PaintEvent であまりにも多くの計算 (ポリゴン パスの計算やグラデーションの生成など) を実行しないようにします。複雑な計算を実行する必要がある場合は、事前計算された結果をメンバー変数またはグローバル変数に保存し、必要に応じて再利用します。
Qt では、QPainter を使用した描画は非常に一般的な操作です。QPainter の API を理解し、ベスト プラクティスに従って使用すると、複雑なグラフィックスやテキスト レイアウトを簡単に作成し、効率的な方法で画面にレンダリングできます。## QPainter と Qt コンポーネント
Qt アプリケーションでは、ウィンドウに直接描画するだけでなく、QPainter を使用して Qt コンポーネント (QPushButton、QLabel、QGraphicsScene など) を描画することもできます。
描画はQWidgetを継承しpaintEvent関数を実装することで共通の方法となります。上位レベルのコンポーネントを使用している場合は、コンポーネントのレンダリングを制御するために、より具体的な描画関数 (QStylePainter::drawControl や QStyle::drawPrimitive など) をオーバーライドする必要がある場合があります。
以下は、QWidget 上にテキスト文字列を描画する方法を示す簡単な例です。
void MyWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QFont font;
font.setPointSize(24);
font.setBold(true);
painter.setFont(font);
QString text = "Hello, world!";
QRect rect = painter.boundingRect(0, 0, width(), height(), Qt::AlignCenter, text);
painter.drawText(rect, text, Qt::AlignCenter);
}
上記のコードでは、QPainter を QWidget インスタンスに直接渡し、paintEvent 関数でテキストを描画します。
上位レベルの Qt コンポーネントでは、通常、QStylePainter クラスまたは QPainterPath クラスを使用してコンポーネントのスタイルとジオメトリを制御します。以下は、QStylePainter を使用して QPushButton の外観をカスタマイズする方法を示す例です。
void MyButton::paintEvent(QPaintEvent *event)
{
QStylePainter painter(this);
QStyleOptionButton option;
painter.drawControl(QStyle::CE_PushButton, option);
}
上記のコードでは、カスタム QPushButton サブクラスを定義し、QStylePainter を使用してPaintEvent 関数で描画します。QStyleOptionButton オブジェクトはボタンの状態とテキストを指定するために使用され、QStylePainter のdrawControl 関数を呼び出してボタンを描画します。
要約する
Qt の QPainter は、幾何学的形状、テキスト、画像をウィンドウや Qt コンポーネントにレンダリングするために使用できる強力なグラフィック描画ツールです。鉛筆の幅、ブラシの色、フォントなどのプロパティを設定することで描画プロセスを制御したり、QPainterPath タイプを使用して複雑な形状を作成したりできます。
最高のパフォーマンスを得るには、必ずベスト プラクティスに従い、形状の計算と描画に最適化されたアルゴリズムを使用してください。描画能力にさらに優れている場合は、OpenGL や Vulkan などのプロ仕様のライブラリを描画に使用することを検討してください。この記事で説明した基本機能に加えて、QPainter にはさらに多くの高度な機能があります。
たとえば、QPainter はクリッピング関数もサポートしており、QPainter::setClipRect() または QPainter::setClipPath() 関数を通じて描画領域を四角形または Qt パスに制限できます。これは、ウィンドウ全体にレンダリングする必要がなく、さまざまな部分に色やパターンをペイントする場合に便利です。
QPainter は、回転、スケーリング、移動などのグラフィックスへの変換の適用もサポートしており、これは QTransform オブジェクトを使用して実現できます。QPainter::setWorldTransform() 関数を使用して QPainter に変換を適用し、QPainter::resetTransform() 関数を使用してデフォルトの状態にリセットできます。
グラフィックスにブレンディング効果を適用する必要がある場合、QPainter はこれもサポートします。QPainter::setCompositionMode() 関数を使用して、描画操作を既存のキャンバス コンテンツと組み合わせて透明効果を生成したり、他のブレンド モードを使用してさまざまな効果を実現したりできます。
最後に重要なことですが、Qt ドキュメントには、QPainter の使用方法を詳しく説明する追加の例、チュートリアル、説明が大量にあります。初心者でも経験豊富な Qt 開発者でも、その恩恵を受けることができます。
この記事が QPainter への理解を深め、グラフィック描画に QPainter をより良く使用するのに役立つことを願っています。