C++GUI Qt 4学習ノート(八)


        Qt       ,Qt          QPainter  。QPainter         ( 、 、   ),         、     。  QPainter         ,     、    、          。QPainter       ,    、  、     。

QPInterは「図形描画装置」(QWidget、QPIxmap、QImage、QSvgGenerator)に描くこともできるし、QPInterと一緒に使用してファイルを印刷したりPDFドキュメントを作成したりすることもできます.
QWidgetの再実装::PaintEvent()は、ウィンドウコンポーネントをカスタマイズし、外観を自由に制御するために使用できます.
1つの一般的な要件は、2 Dパネルに大量の、軽量レベルの、ユーザーが対話できる任意の形状のアイテムを表示することです.
OpenGLコマンドを使用して、Qpainterの代わりに使用できます.OPenGLは3 Dグラフィックを描く標準ライブラリです.
8.1 Qpainterで図面を描く
図面デバイスに図面を描画するには、ポインタをデバイスに転送するQpainterを作成する必要があります.
Qpainterのdrawを使って...()関数は、さまざまな形を描くことができます.描画の効果はQpainterの設定によって異なります.3つの主な設定はブラシ、ブラシ、フォントです.
①ブラシは線と縁を描くのに使います.Qpen,設定属性setPen()
②ブラシで幾何学的形状を塗りつぶすパターン.QBrush,設定属性setBrush()
③文字の描画に使用するフォント.QFont,属性setFont()の設定
楕円を描画するには:
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setPen(QPen(Qt::black,12,Qt::DashDotLine,Qt::RoundCap));
painter.setBrush(QBrush(Qt::green,Qt::SolidPattern));
painter.drawEllipse(80,80,400,240);

setRenderHint(Qpainter::Antialiasing,true)は、この特性をサポートするプラットフォームおよびデバイス上でスムーズなエッジを得るために、反転を有効にすることができる.
QpainterPathクラスは、基本的なグラフィック要素を接続することによって、任意のベクトルグラフィックを決定することができる:直線、楕円、多角形などの描画パス.描画力は基本的なシンボルであり、任意のグラフィックまたはグラフィックの組み合わせは描画パスで記述できます.パスはエッジを決定し、エッジによってロックされた領域はブラシで埋めることができます.
現代の応用では、グラデーション充填は単色充填の流行の代替品となっている.グラデーション塗りは、2つ以上の色の間を滑らかにしすぎるように、色の差を利用します.
Qtは3種類のグラデーションをサポートします.
線形グラデーションは、2つの制御点によって定義され、この2つの点を接続する線上に一連の色のブレークポイントがあります.
円錐状のグラデーション.中心点と角度で定義されます.
放射グラデーションは、中心点、半径、焦点、および色ブレークポイントによって定義されます.色は焦点から外側に広がり、焦点は中心点または円内の他の点であってもよい.
Qpainterには他にもグラフィックや文字の描画方法に影響する設定がありますが、ここでは詳しく説明しません.
8.2座標系変換Qpainterのデフォルト座標系では、点(0,0)は図形描画装置の左上隅にあり、x座標は右に成長し、y座標は下に成長する.既定の座標系の各ピクセルは1 x 1サイズの領域を占めます.
理論的には、ピクセルの中心は半ピクセル座標に依存し、1つのピクセルはちょうど4つのピクセルの重なりに位置する.このような効果を必要としない場合には、半画素座標を設定することによって、またはQpainter(+0.5,+0.5)を安くすることによって、このような効果の発生を回避することができる.
Qpainterのビューポートは、物理座標系の下で作成された任意の矩形です.
Qpainterのウィンドウも同じ矩形を指し、論理座標系の下にすぎない.このウィンドウビューポートメカニズムは、ペイントデバイスのサイズと解像度に依存しないペイントコードを記述するのに役立ちます.
[ワールド変換](World Transform)は、ウィンドウ-ビューポート変換以外で使用される変換マトリクスです.ペイントされたアイテムを移動、スケール、回転、またはストレッチできます.
Oventimerウィンドウ部品コード
このOventimerはオーブンのタイマーを真似ていて、オーブンに内蔵された時計です.ユーザーは、「≪スケール|Scale|emdw≫」をクリックして期間を設定できます.ターンホイールは自動的に反時計回りに0に回転し、Oventimerはこの点でtimeout()信号を送信します.
ovenTimer.h
#ifndef OVENTIMER_H
#define OVENTIMER_H

#include <QDateTime>
#include <QWidget>

class QTimer;

class OvenTimer : public QWidget
{
    Q_OBJECT

public:
    OvenTimer(QWidget *parent = 0);

    void setDuration(int secs);
    int duration() const;
    void draw(QPainter *painter);

signals:
    void timeout();

protected:
    void paintEvent(QPaintEvent *event);
    void mousePressEvent(QMouseEvent *event);

private:
    QDateTime finishTime;
    QTimer *updateTimer;
    QTimer *finishTimer;
};

#endif

oventimer.cpp
#include <QtGui>
#include <cmath>

#ifndef M_PI
#define M_PI 3.14159265359
#endif

#include "oventimer.h"

const double DegreesPerMinute = 7.0;
const double DegreesPerSecond = DegreesPerMinute / 60;
const int MaxMinutes = 45;
const int MaxSeconds = MaxMinutes * 60;
const int UpdateInterval = 5;

OvenTimer::OvenTimer(QWidget *parent)
    : QWidget(parent)
{
    finishTime = QDateTime::currentDateTime();	//      

    updateTimer = new QTimer(this);	
    connect(updateTimer, SIGNAL(timeout()), this, SLOT(update()));

    finishTimer = new QTimer(this);
    finishTimer->setSingleShot(true);
    connect(finishTimer, SIGNAL(timeout()), this, SIGNAL(timeout()));
    connect(finishTimer, SIGNAL(timeout()), updateTimer, SLOT(stop()));

    QFont font;
    font.setPointSize(8);	//         
    setFont(font);
}

void OvenTimer::setDuration(int secs)	//                   。
{
    secs = qBound(0, secs, MaxSeconds);	//    0~MaxSeconds

    finishTime = QDateTime::currentDateTime().addSecs(secs);

    if (secs > 0) {
        updateTimer->start(UpdateInterval * 1000);
        finishTimer->start(secs * 1000);
    } else {
        updateTimer->stop();
        finishTimer->stop();
    }
    update();
}

int OvenTimer::duration() const	//             。
{
    int secs = QDateTime::currentDateTime().secsTo(finishTime);
    if (secs < 0)
        secs = 0;
    return secs;
}

void OvenTimer::mousePressEvent(QMouseEvent *event)
{
    QPointF point = event->pos() - rect().center();
    double theta = std::atan2(-point.x(), -point.y()) * 180.0 / M_PI;
    setDuration(duration() + int(theta / DegreesPerSecond));
    update();
}

void OvenTimer::paintEvent(QPaintEvent * /* event */)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    int side = qMin(width(), height());	//            

    painter.setViewport((width() - side) / 2, (height() - side) / 2,
                        side, side);
    painter.setWindow(-50, -50, 100, 100);

    draw(&painter);
}

void OvenTimer::draw(QPainter *painter)
{
    static const int triangle[3][2] = {
        { -2, -49 }, { +2, -49 }, { 0, -47 }
    };
    QPen thickPen(palette().foreground(), 1.5);	//palette().foreground()    
    QPen thinPen(palette().foreground(), 0.5);
    QColor niceBlue(150, 150, 200);

    painter->setPen(thinPen);
    painter->setBrush(palette().foreground());
    painter->drawPolygon(QPolygon(3, &triangle[0][0]));

    QConicalGradient coneGradient(0, 0, -90.0);
    coneGradient.setColorAt(0.0, Qt::darkGray);
    coneGradient.setColorAt(0.2, niceBlue);
    coneGradient.setColorAt(0.5, Qt::white);
    coneGradient.setColorAt(1.0, Qt::darkGray);

    painter->setBrush(coneGradient);
    painter->drawEllipse(-46, -46, 92, 92);

    QRadialGradient haloGradient(0, 0, 20, 0, 0);
    haloGradient.setColorAt(0.0, Qt::lightGray);
    haloGradient.setColorAt(0.8, Qt::darkGray);
    haloGradient.setColorAt(0.9, Qt::white);
    haloGradient.setColorAt(1.0, Qt::black);

    painter->setPen(Qt::NoPen);
    painter->setBrush(haloGradient);
    painter->drawEllipse(-20, -20, 40, 40);

    QLinearGradient knobGradient(-7, -25, 7, -25);
    knobGradient.setColorAt(0.0, Qt::black);
    knobGradient.setColorAt(0.2, niceBlue);
    knobGradient.setColorAt(0.3, Qt::lightGray);
    knobGradient.setColorAt(0.8, Qt::white);
    knobGradient.setColorAt(1.0, Qt::black);

    painter->rotate(duration() * DegreesPerSecond);
    painter->setBrush(knobGradient);
    painter->setPen(thinPen);
    painter->drawRoundRect(-7, -25, 14, 50, 99, 49);

    for (int i = 0; i <= MaxMinutes; ++i) {
        if (i % 5 == 0) {
            painter->setPen(thickPen);
            painter->drawLine(0, -41, 0, -44);
            painter->drawText(-15, -41, 30, 30,
                              Qt::AlignHCenter | Qt::AlignTop,
                              QString::number(i));
        } else {
            painter->setPen(thinPen);
            painter->drawLine(0, -42, 0, -44);
        }
        painter->rotate(-DegreesPerMinute);
    }
}

8.3 QImageで高品質図面を描く
図面を描くときは、速度と精度の折衷問題に直面する必要があります.