ピンチで画面を拡大縮小!Qt WidgetsでQPinchGesture::lastCenterPointを使ってジェスチャの中心点を取得する方法


QPinchGesture::lastCenterPoint は、Qt Widgets ライブラリで提供されるタッチジェスチャークラス QPinchGesture のプロパティです。これは、ピンチジェスチャの直前の中心点を QPointF 型で返します。ピンチジェスチャは、ユーザーが画面上の 2 つの点に指を置き、それらを近づけたり離したりすることで実行されるジェスチャです。

用途

QPinchGesture::lastCenterPoint は、ピンチジェスチャの動きをトラッキングしたり、ユーザーのインタラクションに基づいて UI を動的に更新したりするために使用できます。たとえば、次のことができます。

  • ピンチジェスチャの中心点に基づいて、UI 要素の位置を変更する。
  • ピンチジェスチャの中心点に基づいて、ズームインまたはズームアウトを実行する。

class MyWidget : public QWidget {
public:
    MyWidget(QWidget *parent = nullptr);

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

private:
    QPinchGesture *pinchGesture;
    QPointF lastCenterPoint;
};

MyWidget::MyWidget(QWidget *parent) : QWidget(parent) {
    pinchGesture = new QPinchGesture(this);
    connect(pinchGesture, &QPinchGesture::gestureUpdated, this, &MyWidget::onGestureUpdated);
}

void MyWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        pinchGesture->start(event);
        lastCenterPoint = pinchGesture->centerPoint();
    }
}

void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pinchGesture->state() == QGesture::GestureActive) {
        QPointF currentCenterPoint = pinchGesture->centerPoint();
        qreal deltaX = currentCenterPoint.x() - lastCenterPoint.x();
        qreal deltaY = currentCenterPoint.y() - lastCenterPoint.y();

        // ピンチジェスチャの中心点に基づいて UI を更新
        // ...

        lastCenterPoint = currentCenterPoint;
    }
}

void MyWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        pinchGesture->cancel();
    }
}

この例では、MyWidget クラスは、ピンチジェスチャの中心点に基づいて UI を更新します。 mousePressEvent メソッドは、ピンチジェスチャが開始されたときに lastCenterPoint 変数を初期化します。 mouseMoveEvent メソッドは、ピンチジェスチャがアクティブなときに lastCenterPoint 変数を更新し、UI を更新します。

  • QPinchGesture::lastCenterPoint は、ピンチジェスチャがアクティブな場合にのみ有効です。ジェスチャが開始されていない場合、または終了した場合、このプロパティは不定の値を返します。
  • QPinchGesture::lastCenterPoint は、グローバル座標系で返されます。ウィジェット座標系に変換するには、mapToLocal メソッドを使用する必要があります。
  • QPinchGesture::lastCenterPoint は、ピンチジェスチャが開始された直後の時点の値を返します。その後、ジェスチャが更新されるたびに更新されます。


ピンチジェスチャの中心点に基づいて画像をズームする

class MyWidget : public QWidget {
public:
    MyWidget(QWidget *parent = nullptr);

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

private:
    QPinchGesture *pinchGesture;
    QImage image;
    qreal scaleFactor = 1.0;
};

MyWidget::MyWidget(QWidget *parent) : QWidget(parent) {
    image = QImage(":/image.png"); // 画像ファイルを読み込む

    pinchGesture = new QPinchGesture(this);
    connect(pinchGesture, &QPinchGesture::gestureUpdated, this, &MyWidget::onGestureUpdated);
}

void MyWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        pinchGesture->start(event);
    }
}

void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pinchGesture->state() == QGesture::GestureActive) {
        qreal delta = pinchGesture->scaleFactor();
        scaleFactor *= delta;

        // 画像をスケーリング
        // ...

        update();
    }
}

void MyWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        pinchGesture->cancel();
    }
}

void MyWidget::paintEvent(QPaintEvent *event) {
    QPainter painter(this);

    // スケーリングされた画像を描画
    painter.scale(scaleFactor, scaleFactor);
    painter.drawImage(0, 0, image);
}
class MyWidget : public QWidget {
public:
    MyWidget(QWidget *parent = nullptr);

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

private:
    QPinchGesture *pinchGesture;
    QPixmap map;
    qreal rotationAngle = 0.0;
};

MyWidget::MyWidget(QWidget *parent) : QWidget(parent) {
    map = QPixmap(":/map.png"); // 地図画像を読み込む

    pinchGesture = new QPinchGesture(this);
    connect(pinchGesture, &QPinchGesture::gestureUpdated, this, &MyWidget::onGestureUpdated);
}

void MyWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        pinchGesture->start(event);
    }
}

void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pinchGesture->state() == QGesture::GestureActive) {
        qreal deltaRotation = pinchGesture->rotationAngle() - lastRotationAngle;
        rotationAngle += deltaRotation;

        // 地図を回転
        // ...

        update();

        lastRotationAngle = pinchGesture->rotationAngle();
    }
}

void MyWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        pinchGesture->cancel();
    }
}

void MyWidget::paintEvent(QPaintEvent *event) {
    QPainter painter(this);

    // 回転された地図を描画
    painter.translate(width() / 2, height() / 2);
    painter.rotate(rotationAngle);
    painter.drawPixmap(-map.width() / 2, -map.height() / 2, map);
}


QGestureEvent の lastCenterPoint プロパティを使用する

QPinchGesture は QGesture のサブクラスであるため、QPinchGesture::lastCenterPoint プロパティに加えて、QGestureEvent::lastCenterPoint プロパティも使用できます。このプロパティは、すべてのジェスチャクラスで共通であり、ジェスチャのタイプに関係なく使用できます。

void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pinchGesture->state() == QGesture::GestureActive) {
        QGestureEvent *gestureEvent = pinchGesture->gestureEvent();
        QPointF centerPoint = gestureEvent->lastCenterPoint();

        // ピンチジェスチャの中心点に基づいて UI を更新
        // ...
    }
}

QPinchGesture::centerPoint() メソッドを使用する

QPinchGesture::centerPoint() メソッドは、現在のピンチジェスチャの中心点を返します。このメソッドは、ジェスチャがアクティブな場合のみ有効です。

void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pinchGesture->state() == QGesture::GestureActive) {
        QPointF centerPoint = pinchGesture->centerPoint();

        // ピンチジェスチャの中心点に基づいて UI を更新
        // ...
    }
}

QPinchGesture::totalScaleFactor() と QPinchGesture::centerPoint() メソッドを使用して、計算する

QPinchGesture::totalScaleFactor() メソッドは、ピンチジェスチャの累積的なスケールファクターを返します。QPinchGesture::centerPoint() メソッドは、現在のピンチジェスチャの中心点を返します。これらの 2 つの値を使用して、前のピンチジェスチャの中心点を計算できます。

void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pinchGesture->state() == QGesture::GestureActive) {
        qreal totalScaleFactor = pinchGesture->totalScaleFactor();
        QPointF centerPoint = pinchGesture->centerPoint();

        // 前回のピンチジェスチャの中心点を計算
        QPointF previousCenterPoint = centerPoint / totalScaleFactor;

        // ピンチジェスチャの中心点に基づいて UI を更新
        // ...
    }
}

どの方法を使用するか

どの方法を使用するかは、状況によって異なります。次の要因を考慮する必要があります。

  • 精度: QPinchGesture::lastCenterPoint プロパティは、高精度な値を返します。QPinchGesture::centerPoint() メソッドと QPinchGesture::totalScaleFactor() メソッドを使用して計算された中心点は、精度が低くなる可能性があります。
  • ジェスチャの状態: QPinchGesture::lastCenterPoint プロパティは、ジェスチャがアクティブな場合のみ有効です。ジェスチャの状態を把握する必要がある場合は、QPinchGesture::state() メソッドを使用する必要があります。
  • ジェスチャのタイプ: QPinchGesture::lastCenterPoint プロパティは、ピンチジェスチャ専用に設計されています。他のタイプのジェスチャを使用する場合は、QGestureEvent::lastCenterPoint プロパティを使用する必要があります。
  • QPinchGesture::lastCenterPoint プロパティは、ピンチジェスチャが開始された直後の時点の値を返します。その後、ジェスチャが更新されるたびに更新されます。
  • QPinchGesture::lastCenterPoint プロパティは、グローバル座標系で返されます。ウィジェット座標系に変換するには、mapToLocal メソッドを使用する必要があります。