このページでは

画像ジェスチャーの例

ウィジェットでの簡単なジェスチャーの使用例を示します。

この例では、ウィジェットでジェスチャーを有効にし、ジェスチャー入力を利用してアクションを実行する方法を示します。

花の画像に対するジェスチャー入力

アプリケーションのユーザーインターフェースを作成するために、MainWidget クラスとImageWidget クラスの2つのクラスを使用します。MainWidget クラスは、ImageWidget クラスのコンテナとして単純に使用されます。 クラスは、ジェスチャー入力を受け付けるように設定します。ここではジェスチャーの使用方法に焦点を当てるため、ImageWidget クラスの実装に重点を置いて説明します。

ImageWidgetクラスの定義

ImageWidget クラスは、QWidget の単純なサブクラスであり、汎用的なQWidget::event()ハンドラ関数に加え、いくつかのより具体的なイベントハンドラを再実装しています:

class ImageWidget : public QWidget
{
    Q_OBJECT

public:
    ImageWidget(QWidget *parent = nullptr);
    void openDirectory(const QString &url);
    void grabGestures(const QList<Qt::GestureType> &gestures);

protected:
    bool event(QEvent *event) override;
    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void mouseDoubleClickEvent(QMouseEvent *event) override;

private:
    bool gestureEvent(QGestureEvent *event);
    void panTriggered(QPanGesture*);
    void pinchTriggered(QPinchGesture*);
    void swipeTriggered(QSwipeGesture*);
    ...
};

また、ウィジェットに送信されるジェスチャーイベントの管理を支援するためのプライベートなヘルパー関数 `gestureEvent()` と、ジェスチャーに基づいてアクションを実行するための 3 つの関数 `panTriggered()`、`pinchTriggered() `、および `swipeTriggered()` を実装しています。

ImageWidget クラスの実装

ウィジェットのコンストラクタでは、まず画像の表示方法を制御するために使用されるさまざまなパラメータを設定します。

ImageWidget::ImageWidget(QWidget *parent)
    : QWidget(parent), position(0), horizontalOffset(0), verticalOffset(0)
    , rotationAngle(0), scaleFactor(1), currentStepScaleFactor(1)
{
    setMinimumSize(QSize(100, 100));
}

QWidget::grabGesture() を呼び出し、必要なジェスチャーのタイプを指定することで、ウィジェットに対して3つの標準ジェスチャーを有効にします。これらはアプリケーションのデフォルトのジェスチャー認識機能によって認識され、イベントがウィジェットに送信されます。

QWidget はジェスチャー用の特定のイベントハンドラを定義していないため、ウィジェットはジェスチャーイベントを受信するために、汎用的なQWidget::event()を再実装する必要があります。

bool ImageWidget::event(QEvent *event)
{
    if (event->type() == QEvent::Gesture)
        return gestureEvent(static_cast<QGestureEvent*>(event));
    return QWidget::event(event);
}

イベントハンドラを実装して、ジェスチャイベントをそのタスクのために特別に作成されたプライベート関数に委譲し、その他のすべてのイベントをQWidget の実装に渡します。

gestureHandler() 関数は、新しく渡されたQGestureEvent から提供されたジェスチャーを検査します。ウィジェットでは、特定の時点で特定のタイプのジェスチャーを1つしか使用できないため、QGestureEvent::gesture()関数を使用して各ジェスチャータイプを確認できます:

bool ImageWidget::gestureEvent(QGestureEvent *event)
{
    qCDebug(lcExample) << "gestureEvent():" << event;
    if (QGesture *swipe = event->gesture(Qt::SwipeGesture))
        swipeTriggered(static_cast<QSwipeGesture *>(swipe));
    else if (QGesture *pan = event->gesture(Qt::PanGesture))
        panTriggered(static_cast<QPanGesture *>(pan));
    if (QGesture *pinch = event->gesture(Qt::PinchGesture))
        pinchTriggered(static_cast<QPinchGesture *>(pinch));
    return true;
}

特定の種類のジェスチャーに対してQGesture オブジェクトが渡された場合、そのジェスチャーオブジェクトを適切なQGesture サブクラスにキャストし、それを処理するための専用関数を呼び出します。

標準的なジェスチャーがアプリケーションによってどのように解釈されるかを示すために、ユーザーがディスプレイや入力デバイス上で2本の指を動かす際のピンチジェスチャーを処理するpinchTriggered() 関数の実装例を紹介します:

void ImageWidget::pinchTriggered(QPinchGesture *gesture)
{
    QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
    if (changeFlags & QPinchGesture::RotationAngleChanged) {
        qreal rotationDelta = gesture->rotationAngle() - gesture->lastRotationAngle();
        rotationAngle += rotationDelta;
        qCDebug(lcExample) << "pinchTriggered(): rotate by" <<
            rotationDelta << "->" << rotationAngle;
    }
    if (changeFlags & QPinchGesture::ScaleFactorChanged) {
        currentStepScaleFactor = gesture->totalScaleFactor();
        qCDebug(lcExample) << "pinchTriggered(): zoom by" <<
            gesture->scaleFactor() << "->" << currentStepScaleFactor;
    }
    if (gesture->state() == Qt::GestureFinished) {
        scaleFactor *= currentStepScaleFactor;
        currentStepScaleFactor = 1;
    }
    update();
}

QPinchGesture クラスは、2つのタッチポイント間の距離の変化をズーム倍率として、角度の差を画像に適用する回転として解釈するためのプロパティを提供します。タッチポイント間の中心点は画像のドラッグに使用することもできますが、この例ではその目的にはパンジェスチャーを使用します。

scaleFactor() は、あるイベントから次のイベントにかけてズームがどれだけ変化すべきかを表す相対値であるのに対し、totalScaleFactor() は、ジェスチャーの開始以来表現されてきたズーム量を表します。 タッチポイントが離され、別のジェスチャーが開始されると、totalScaleFactor() は再び1.0から開始されます。この場合、totalScaleFactor() をcurrentStepScaleFactor 変数に保存し、paintEvent() で画像の拡大縮小に使用できるようにします。あるいは、ピンチハンドラ内で、保存された合計拡大縮小率にscaleFactor() を単純に掛け合わせることも可能です。

対照的に、rotationAngle() はピンチジェスチャが開始されてからの回転量を表し、lastRotationAngle() は前回の値を提供します。 したがって、増分(デルタ)を得るためには差し引きを行う必要があります。ユーザーが新しいピンチジェスチャーを開始すると、rotationAngle() はゼロから始まりますが、画像は現在の角度から回転を開始させたいところです。これは、保存されているrotationAngle にデルタを加算することで実現されます(この値はpaintEvent() で適用されます)。 もし単にtotalRotationAngle() を保存済みのrotationAngle に代入してしまうと、新しいジェスチャーが行われた際に、画像は再び回転を始める前に、正立した向きにリセットされてしまいます。しかし、ジェスチャーが開始されてからの回転角度を保存し、paintEvent() 内のrotationAngle にそれを加算することは可能です。これは、ジェスチャーが開始されてからのズーム量を保存するのと同じ仕組みです。

この例のパンおよびスワイプジェスチャーも、それぞれ別の関数で処理されており、渡されたQGesture オブジェクトのプロパティの値を使用しています。

void ImageWidget::paintEvent(QPaintEvent*)
{
    QPainter p(this);

    if (files.isEmpty() && !path.isEmpty()) {
        p.drawText(rect(), Qt::AlignCenter|Qt::TextWordWrap,
                         tr("No supported image formats found"));
        return;
    }

    const qreal iw = currentImage.width();
    const qreal ih = currentImage.height();
    const qreal wh = height();
    const qreal ww = width();

    p.translate(ww / 2, wh / 2);
    p.translate(horizontalOffset, verticalOffset);
    p.rotate(rotationAngle);
    p.scale(currentStepScaleFactor * scaleFactor, currentStepScaleFactor * scaleFactor);
    p.translate(-iw / 2, -ih / 2);
    p.drawImage(0, 0, currentImage);
}

paintEvent() において、scaleFactor はピンチジェスチャ開始前のズームレベルを表し、currentStepScaleFactor はピンチジェスチャの進行中に追加されるズーム倍率を表します。一方、回転については、現在の rotationAngle のみが保存されます。水平および垂直のオフセットは、パンジェスチャによって画像がドラッグされた距離を表します。

サンプルプロジェクト @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.