アナログ時計

アナログ時計の例では、カスタムウィジェットの内容を描画する方法を示します。

アナログ時計の例のスクリーンショット

この例では、カスタムウィジェットの描画を簡単にするために、QPainter の変換とスケーリングの機能をどのように使用できるかも示しています。

アナログ時計クラスの定義

AnalogClock クラスは、毎秒自動的に更新される時針、分針、秒針を備えた時計ウィジェットを提供します。QWidget をサブクラス化し、標準のpaintEvent() 関数を再実装して時計の文字盤を描画します:

class AnalogClock : public QWidget
{
    Q_OBJECT

public:
    AnalogClock(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent *event) override;
};

AnalogClockクラスの実装

ウィジェットが構築されると、現在時刻を記録するために1秒タイマーをセットアップし、タイマーがtimeout ()シグナルを発すると時計の文字盤が更新されるように、標準のupdate ()スロットに接続します。最後に、ウィジェットのサイズを変更して、適切なサイズで表示されるようにします。

AnalogClock::AnalogClock(QWidget *parent)
    : QWidget(parent)
{
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));
    timer->start(1000);

    setWindowTitle(tr("Analog Clock"));
    resize(200, 200);
}

paintEvent() 関数は、ウィジェットのコンテンツを更新する必要があるときに呼び出されます。これは、ウィジェットが最初に表示されるときと、カバーされた後に露出されるときに発生しますが、ウィジェットのupdate ()スロットが呼び出されるときにも実行されます。タイマーのtimeout() シグナルをこのスロットに接続したので、少なくとも1秒に1回は呼び出されます。

ペインターのセットアップと時計の描画を行う前に、まず、時針、分針、秒針に使用するQPoints とQColors のリストを3つ定義します。palette()関数を使い、ライトモードとダークモードの両方で、ウィンドウの残りの部分に合う適切な色を取得する。時針と分針は前景色で描かれ、秒針はアクセント・カラーで描かれます。

また、ウィジェットの中に時計の文字盤が収まるように、ウィジェットの最も短い辺の長さを決定します。また、描画を開始する前に現在時刻を決定しておくと便利です。

void AnalogClock::paintEvent(QPaintEvent *)
{
    static const QPoint hourHand[4] = {
        QPoint(5, 14),
        QPoint(-5, 14),
        QPoint(-4, -71),
        QPoint(4, -71)
    };
    static const QPoint minuteHand[4] = {
        QPoint(4, 14),
        QPoint(-4, 14),
        QPoint(-3, -89),
        QPoint(3, -89)
    };

    static const QPoint secondsHand[4] = {
       QPoint(1, 14),
       QPoint(-1, 14),
       QPoint(-1, -89),
       QPoint(1, -89)
    };

    const QColor hourColor(palette().color(QPalette::Text));
    const QColor minuteColor(palette().color(QPalette::Text));
    const QColor secondsColor(palette().color(QPalette::Accent));

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

カスタムウィジェットの内容は、QPainter を使って描画します。ペインターは、QPaintDevice に描画するために使用できますが、通常はウィジェットで使用するため、ペインターのコンストラクタにウィジェットのインスタンスを渡します。

    QPainter painter(this);
    QTime time = QTime::currentTime();

アンチエイリアスをオンにするために、QPainter::AntialiasingQPainter::setRenderHint() を呼び出します。これにより、対角線の描画がよりスムーズになります。

    painter.setRenderHint(QPainter::Antialiasing);

平行移動は原点をウィジェットの中心に移動させ、スケール操作は次の描画操作がウィジェット内に収まるようにスケーリングされるようにします。ここでは、-100から100の間のx座標とy座標を使用できるようにスケールファクターを使用し、これらの座標がウィジェットの最短辺の長さに収まるようにします。

    painter.translate(width() / 2, height() / 2);
    painter.scale(side / 200.0, side / 200.0);

コードをシンプルにするために、固定サイズの時計の文字盤を描き、それがウィジェットの中心に来るように位置とスケールを決めます。

ペインターは、paintイベント中に行われるすべての変換を処理し、すべてが正しく描画されるようにします。カスタムウィジェットの内容を描画するためだけに手動で計算するよりも、ペインタにトランスフォームを任せる方が簡単なことがよくあります。

輪郭を描きたくないので、ペンをQt::NoPen に設定し、時間表示に適した色のベタブラシを使用します。ブラシは、多角形やその他の幾何学的形状を塗りつぶすときに使用します。

    painter.setPen(Qt::NoPen);
    painter.setBrush(hourColor);

まず時針を描きます。このとき、現在の時分によって決まる度数だけ、座標系を反時計回りに回転させる数式を使います。つまり、針は必要な分だけ時計回りに回転して表示される。回転の前後に変換行列を保存して復元するのは、以前の回転を考慮せずに分針を配置したいからである。

    painter.save();
    painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
    painter.drawConvexPolygon(hourHand, 4);
    painter.restore();

時針と同じ色で時計の縁にマーカーを引く。それぞれのマーカーを描いてから座標系を回転させ、ペインターが次のマーカーを描けるようにする。

    for (int i = 0; i < 12; ++i) {
        painter.drawRect(73, -3, 16, 6);
        painter.rotate(30.0);
    }

分針も時針と同じように回転させて描く。

    painter.setBrush(minuteColor);

    painter.save();
    painter.rotate(6.0 * time.minute());
    painter.drawConvexPolygon(minuteHand, 4);
    painter.restore();

秒針も同様に描き、視覚的なハイライトとして2つのシクルを加えます。

    painter.setBrush(secondsColor);

    painter.save();
    painter.rotate(6.0 * time.second());
    painter.drawConvexPolygon(secondsHand, 4);
    painter.drawEllipse(-3, -3, 6, 6);
    painter.drawEllipse(-5, -68, 10, 10);
    painter.restore();

最後に、時計の縁に分と秒を示すマーカーを描く。今回は線として描くので、ペンをそれぞれの色に設定する。

    painter.setPen(minuteColor);

    for (int j = 0; j < 60; ++j) {
        painter.drawLine(92, 0, 96, 0);
        painter.rotate(6.0);
    }

プロジェクト例 @ code.qt.io

©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。