【Qt Widgets】ジェスチャー処理:QGestureEvent::accept()を徹底解説!


QGestureEvent::accept()は、Qt Widgetsにおけるジェスチャーイベント処理において重要な役割を果たすメソッドです。このメソッドは、特定のジェスチャーまたはジェスチャーツイープをイベントレシーバーが受け入れることを示します。受け入れられたジェスチャーは、そのイベントレシーバーによって処理されます。受け入れられないジェスチャーは、親ウィジェットに伝達されます。

詳細

QGestureEvent::accept()には、2つのオーバーロードメソッドが存在します。

  • accept(Qt::GestureType gestureType): 特定のQt::GestureTypeを受け入れることを示します。
  • accept(QGesture *gesture): 特定のQGestureオブジェクトを受け入れることを示します。

いずれのメソッドも、QGestureEventオブジェクトに含まれるジェスチャーまたはジェスチャーツイープに適用されます。

以下の例は、QGestureEvent::accept()を使用して、タップジェスチャーを処理する方法を示しています。

void MyWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        QGestureEvent *gestureEvent = new QGestureEvent(this, event->localPos());
        QTapGesture *tapGesture = new QTapGesture(gestureEvent);
        gestureEvent->ignore(tapGesture);
        connect(tapGesture, SIGNAL(stateChanged(QGesture::GestureState)), this, SLOT(handleTapGesture(QGesture::GestureState)));
    }
}

void MyWidget::handleTapGesture(QGesture::GestureState state)
{
    if (state == QGesture::Started) {
        // タップジェスチャーが開始されたときに処理を実行
    } else if (state == QGesture::Accepted) {
        // タップジェスチャーが受け入れられたときに処理を実行
    } else if (state == QGesture::Finished) {
        // タップジェスチャーが終了したときに処理を実行
    }
}

この例では、mousePressEvent()内で、左クリックイベントが発生したときにQGestureEventオブジェクトを作成します。次に、QTapGestureオブジェクトを作成し、QGestureEventオブジェクトに関連付けます。ignore()メソッドを使用して、QTapGestureオブジェクトがデフォルトで受け入れられないように設定します。最後に、stateChanged()シグナルをhandleTapGesture()スロットに接続します。

handleTapGesture()スロットは、QGestureオブジェクトの状態に応じて処理を実行します。stateStartedの場合、タップジェスチャーが開始されたときに処理を実行します。stateAcceptedの場合、タップジェスチャーが受け入れられたときに処理を実行します。stateFinishedの場合、タップジェスチャーが終了したときに処理を実行します。

  • Qt Widgetsには、さまざまなジェスチャータイプを処理するためのクラスが用意されています。詳細については、Qtドキュメントを参照してください。
  • QGestureEvent::accept()は、ジェスチャーイベント処理の重要な部分ですが、唯一の部分ではありません。ジェスチャーの状態を監視し、適切なタイミングで処理を実行することも重要です。


スワイプジェスチャーの検出

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:
    QGesture *currentGesture;
    QPointF startPosition;
};

MyWidget::MyWidget(QWidget *parent) : QWidget(parent) {
    setAcceptDrops(true);
}

void MyWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        currentGesture = new QPanGesture(this, event->localPos());
        startPosition = event->localPos();
        connect(currentGesture, SIGNAL(stateChanged(QGesture::GestureState)), this, SLOT(handlePanGesture(QGesture::GestureState)));
    }
}

void MyWidget::mouseMoveEvent(QMouseEvent *event) {
    if (currentGesture) {
        currentGesture->update(event->localPos());
    }
}

void MyWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (currentGesture) {
        currentGesture->stateChanged(QGesture::Finished);
        currentGesture = nullptr;
    }
}

void MyWidget::handlePanGesture(QGesture::GestureState state) {
    if (state == QGesture::Started) {
        // スワイプジェスチャーが開始されたときに処理を実行
    } else if (state == QGesture::Accepted) {
        QPanGesture *panGesture = static_cast<QPanGesture *>(currentGesture);
        QPointF delta = panGesture->delta();

        // スワイプの方向と距離に基づいて処理を実行
        if (delta.x() > 0.0) {
            // 右方向にスワイプ
        } else if (delta.x() < 0.0) {
            // 左方向にスワイプ
        }

        if (delta.y() > 0.0) {
            // 下方向にスワイプ
        } else if (delta.y() < 0.0) {
            // 上方向にスワイプ
        }
    } else if (state == QGesture::Finished) {
        // スワイプジェスチャーが終了したときに処理を実行
    }
}

この例では、mousePressEvent()内で、左クリックイベントが発生したときにQPanGestureオブジェクトを作成し、QGestureEventオブジェクトに関連付けます。次に、stateChanged()シグナルをhandlePanGesture()スロットに接続します。

handlePanGesture()スロットは、QGestureオブジェクトの状態に応じて処理を実行します。stateStartedの場合、スワイプジェスチャーが開始されたときに処理を実行します。stateAcceptedの場合、スワイプジェスチャーが受け入れられたときに処理を実行します。deltaプロパティを使用して、スワイプの方向と距離を取得できます。stateFinishedの場合、スワイプジェスチャーが終了したときに処理を実行します。

この例では、QGestureEvent::accept()を使用して、ウィジェット上でピンチジェスチャーを検出する方法を示します。

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

protected:
    void touchEvent(QTouchEvent *event) override;

private:
    QGesture *currentGesture;
    qreal scaleFactor = 1.0;
};

MyWidget::MyWidget(QWidget *parent) : QWidget(parent) {
    setAcceptTouchEvents(true);
}

void MyWidget::touchEvent(QTouchEvent *event) {
    if (event->type() == QEvent::TouchBegin || event->type() == QEvent::TouchUpdate) {
        if (event->touchPoints().size() == 2) {
            QPinchGesture *pinchGesture = new QPinchGesture(this, event->touchPoints());
            currentGesture = pinchGesture;
            connect(currentGesture, SIGNAL(stateChanged(QGesture::GestureState)), this, SLOT(handlePinchGesture(QGesture::GestureState


代替方法

  • カスタムジェスチャーレシーバーを作成する: 独自のジェスチャー処理ロジックを実装したい場合は、カスタムジェスチャーレシーバーを作成できます。カスタムジェスチャーレシーバーは、QGestureEventオブジェクトを受け取り、必要に応じて処理できます。
  • ジェスチャーを伝達する: ジェスチャーを親ウィジェットに伝達したい場合は、QGestureEvent::ignore()メソッドを使用せずに、イベントループを継続できます。親ウィジェットは、QGestureEventオブジェクトを受け取り、必要に応じて処理できます。
  • ignore()メソッドを使用する: 特定のジェスチャーを無視したい場合は、QGestureEvent::ignore()メソッドを使用できます。このメソッドは、そのジェスチャーがイベントレシーバーによって処理されないことを示します。

各方法の詳細

  • ignore()メソッド: QGestureEvent::ignore()メソッドは、特定のジェスチャーをイベントレシーバーによって処理されないことを示します。このメソッドは、ジェスチャーを完全に無視したい場合に使用されます。
gestureEvent->ignore(tapGesture);
  • ジェスチャーを伝達する: ジェスチャーを親ウィジェットに伝達するには、QGestureEventオブジェクトを処理せずにイベントループを継続するだけです。親ウィジェットは、QGestureEventオブジェクトを受け取り、必要に応じて処理できます。
// ジェスチャーを処理しない
  • カスタムジェスチャーレシーバーを作成する: カスタムジェスチャーレシーバーを作成するには、QGestureRecognizerクラスを継承する新しいクラスを作成する必要があります。新しいクラスは、stateChanged()シグナルを実装する必要があります。stateChanged()シグナルは、ジェスチャーの状態が変化するたびにemitされます。
class MyGestureRecognizer : public QGestureRecognizer
{
public:
    MyGestureRecognizer(QObject *parent = nullptr);

protected:
    void stateChanged(QGesture::GestureState state);
};

MyGestureRecognizer::MyGestureRecognizer(QObject *parent) : QGestureRecognizer(parent) {}

void MyGestureRecognizer::stateChanged(QGesture::GestureState state)
{
    // カスタムジェスチャー処理ロジックを実装する
}

どの方法を選択するべきか

どの方法を選択するかは、状況によって異なります。

  • 独自のジェスチャー処理ロジックを実装したい場合は、カスタムジェスチャーレシーバーを作成します。
  • ジェスチャーを親ウィジェットに伝達したい場合は、ジェスチャーを伝達します。
  • 特定のジェスチャーを完全に無視したい場合は、ignore()メソッドを使用します。

以下の例は、QGestureEvent::accept()の代わりにignore()メソッドを使用する方法を示しています。

void MyWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        QGestureEvent *gestureEvent = new QGestureEvent(this, event->localPos());
        QTapGesture *tapGesture = new QTapGesture(gestureEvent);
        gestureEvent->ignore(tapGesture);
        connect(tapGesture, SIGNAL(stateChanged(QGesture::GestureState)), this, SLOT(handleTapGesture(QGesture::GestureState)));
    }
}