이미지 제스처 예시
위젯에서 간단한 제스처를 사용하는 방법을 보여줍니다.
이 예제에서는 위젯에 제스처를 활성화하고 제스처 입력을 사용하여 작업을 수행하는 방법을 보여줍니다.
애플리케이션의 사용자 인터페이스를 만들기 위해 MainWidget
와 ImageWidget
두 개의 클래스를 사용합니다. MainWidget
클래스는 단순히 제스처 입력을 받도록 구성할 ImageWidget
클래스의 컨테이너로 사용됩니다. 우리는 제스처가 사용되는 방식에 관심이 있으므로 ImageWidget
클래스의 구현에 집중하겠습니다.
이미지 위젯 클래스 정의
ImageWidget
클래스는 몇 가지 구체적인 이벤트 핸들러와 함께 일반적인 QWidget::event() 핸들러 함수를 재구현하는 간단한 QWidget 서브클래스입니다:
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()
와 제스처에 따라 작업을 수행하는 세 가지 함수를 구현합니다: 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()를 호출하여 위젯의 표준 제스처 중 세 가지를 활성화합니다. 애플리케이션의 기본 제스처 인식기가 이를 인식하고 이벤트가 위젯으로 전달됩니다.
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 에서 제공된 제스처를 검사합니다. 특정 시간에 특정 유형의 제스처는 위젯에서 하나만 사용할 수 있으므로 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 서브클래스로 캐스팅하여 처리합니다.
애플리케이션에서 표준 제스처를 해석하는 방법을 설명하기 위해 사용자가 디스플레이 또는 입력 장치에서 두 손가락을 움직일 때 핀치 제스처를 처리하는 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 클래스는 두 터치 포인트 사이의 거리 변화를 줌 인자로, 각도 델타를 이미지에 적용할 회전으로 해석하는 프로퍼티를 제공합니다. 터치 포인트 사이의 중심점을 사용하여 이미지를 드래그할 수도 있지만 이 예제에서는 팬 제스처를 사용합니다.
scaleFactor()
은 한 이벤트에서 다음 이벤트까지 줌이 얼마나 변해야 하는지를 나타내는 상대 값이고, totalScaleFactor()
은 제스처가 시작된 이후 표현된 줌의 양을 제공합니다. 터치 포인트가 해제되고 다른 제스처가 시작되면 totalScaleFactor()
은 1.0에서 다시 시작됩니다. 이 경우 currentStepScaleFactor
변수에 totalScaleFactor()
을 저장하여 paintEvent()
에서 이미지 크기를 조정하는 데 사용할 수 있도록 합니다. 또는 핀치 핸들러에서 저장된 총 배율에 scaleFactor()
을 곱하는 방법도 있습니다.
반대로 rotationAngle()
은 핀치 제스처가 시작된 이후의 회전량을 나타내며 lastRotationAngle()
은 이전 값을 제공합니다. 따라서 증분 델타를 얻으려면 빼는 작업이 필요합니다. 사용자가 새로운 핀치 제스처를 시작하면 rotationAngle()
은 0에서 시작하고 이미지가 현재 각도부터 회전하기 시작하기를 원합니다. 이는 저장된 rotationAngle
( paintEvent()
에 적용됨)에 델타를 추가하여 달성할 수 있습니다. 단순히 저장된 rotationAngle
에 totalRotationAngle()
을 할당하면 새로운 제스처를 수행하면 이미지가 다시 회전하기 전에 오른쪽 위로 향하도록 재설정됩니다. 하지만 제스처가 시작된 이후 회전 각도를 저장하고 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는 핀치 제스처가 진행 중인 동안의 추가 확대/축소 계수를 나타냅니다. 그러나 회전의 경우 현재 회전 각도만 저장됩니다. 수평 및 수직 오프셋은 이동 제스처로 이미지가 드래그된 거리를 나타냅니다.
© 2025 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.