Qt Mouse Wheel Event 처리하기

개요

 이번 시간에는 다양한 곳에서 사용되는 마우스 휠 이벤트 (Wheel Event)Python +PyQt5에서 어떻게 감지하고 활용하는지 살펴보겠습니다.

 

마우스 휠 이벤트가 필요한 대표적인 경우는 다음과 같습니다.

  • 화면 이동, 웹페이지 업, 다운 처리

  • 이미지 줌인, 줌 아웃 

 

먼저 완성된 결과물을 먼저 살펴보면 아래와 같습니다.

[마우스 휠 이벤트 처리]

 

아래와 같은 순서로 진행됩니다.

1. 빈 위젯을 하나 생성

2. Ctrl 키 눌러진 상태에서 휠 이벤트가 발생 (줌인, 아웃으로 처리)

3. Ctrl 키 떨어진 상태에서 휠 이벤트가 발생 (일반적인 스크롤로 처리)

4. 휠 이벤트 발생시 Ctrl 키 여부를 감지, 각 변수에 저장 후 출력

사실 이나 일반스크롤로 처리하나 둘 다 개념은 같지만 줌의 경우는 휠 이벤트시(Ctrl O) 1씩 변화량을 가져가고 스크롤(Ctrl X) 은 좀 더 변화량이 크게 적용해 보았습니다.


개발 환경

  •  Windows 10 Pro 64bit

  • Python 3.8.8 64bit, Pycharm 2021.1

  • PyQt 5.15.3


소스코드

from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPainter, QFont
from PyQt5.QtCore import Qt, QPointF
import sys

QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)

class Form(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle('Mouse Wheel Event')
        self.bCtrl = False
        self.deg = QPointF()
        self.zoom = QPointF()

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)

        f = QFont('arial', 20)
        qp.setFont(f)

        ctrltxt = f'Ctrl Key Pressed:{self.bCtrl}'
        zoomtxt = f'Zoom X:{self.zoom.x()}, Zoom Y:{self.zoom.y()}'
        degtxt  = f'Deg X:{self.deg.x()}, Deg Y:{self.deg.y()}'
        qp.drawText(self.rect(), Qt.AlignCenter, ctrltxt+'\n'+zoomtxt+'\n'+degtxt)
        qp.end()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Control:
            self.bCtrl = True
        self.update()

    def keyReleaseEvent(self, e):
        if e.key() == Qt.Key_Control:
            self.bCtrl = False
        self.update()

    def wheelEvent(self, e):
        if self.bCtrl:
            self.zoom += e.angleDelta() / 120
        else:
            self.deg += e.angleDelta() / 8

        self.update()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Form()
    w.show()
    sys.exit(app.exec_())

[라인 1~6]

필요한 모듈을 불러오고, 4K 모니터를 위한 해상도 설정을 진행합니다.


[라인 8~15]

QWidge에서 상속받은 Form Class의 선언과 생성자 함수입니다.

Ctrl키의 눌러짐을 감지할 bool type 변수, 마우스 휠 이벤트를 2가지 타입 (줌, 스크롤)으로 저장할 QPointF type 변수를 선언합니다.

 

[라인 17~28]

QWidet의 paintEvent() 에 대한 오버라이딩이며 위젯을 새로 그릴 필요가 있을때 마다 호출되는 함수입니다.

QPainter 객체를 생성하고 Ctrl 키 눌러짐 여부, Zoom값, 스크롤 값(Deg)을 fstring으로 정리해 화면에 출력합니다.


[라인 30~33]

QWidget의 keyPressEvent() 에 대한 오버라이딩이며 위젯에 키보드가 눌러진 경우 호출되는 함수입니다.

Ctrl 키가 눌러진 경우 self.bCtrl 변수를 참으로 설정합니다.

self.update()는 QWidget의 paintEvent() 함수를 호출해 Ctrl 키의 눌러짐 여부를 바로 화면에 고쳐 쓰도록 합니다.


[라인 35~38]

Ctrl 키의 떨어짐을 감지해 변수를 설정합니다.


[라인 40~46]

QWidget의 wheelEvent() 에 대한 오버라이딩이며 위젯에 마우스 휠 이벤트가 발생된 경우 호출되는 함수입니다.

이때 전달인자로 QWheelEvent 객체인 e가 전달되며, 이 클래스는 멤버함수로 마우스 휠 회전 변화량을 돌려주는 angleDelta(), pixelDelta() 두개의 함수를 갖습니다.

[Qt WheelEvent 설명 : 출처 Qt]

다만 pixcelDelta() 함수는 High-resolution 을 지원하는 운영체제 (예 : macOS) 만 사용가능하다고 합니다.

따라서 저는 Windows를 사용하므로 예제에서 angleDelta() 를 사용하였습니다.

이 함수는 마우스 휠 각도 변화량이 120도 기준으로 리턴되므로 아래와 같이 적용하였습니다.

  • 줌인, 아웃 = 120 / 120, 즉 변화량이 1도

  • 스크롤 = 120 / 8, 즉 변화량이 15도

물론 이 값은 편리한대로 값을 조절해 사용하면 됩니다.

예) 120 / 12 = 변화량 10도

Qt 의 문서에 따르면 대부분의 경우 마우스 휠 스크롤은 15도가 기준이라고 합니다.

모든 마우스가 수직(Y), 수평(X) 휠 스크롤이 다 지원되지는 않으며, 제가 사용하는 마우스는 수평스크롤이 지원되는 모델이라 X값이 변하는 모습이 확인 가능합니다.  

 

[마우스 휠 방향]

[라인 48~52]

코드가 시작되는 메인함수이며, QApplication 객체와 QWidget에서 상속받은 Form Class의 객체를 생성해 앱을 실행합니다.


이상으로 모든 설명을 마칩니다.

앱을 실행하고 마우스 휠을 조작하면 화면에 변화량이 표시됩니다.

감사합니다.

댓글

이 블로그의 인기 게시물

Qt Designer 설치하기

PyQt5 기반 동영상 플레이어앱 만들기