QWidget 의 전역 이벤트(installEventFilter) 처리방법

개요

Qt 의 Class를 이용 앱 제작시, 

QWidget에서 상속받은 컨트롤 ( QListWidget, QTableWidget, QLineEdit 등) 클래스의 이벤트 처리를 위해 서브 클래싱 (Subclassing) 을 자주 사용하게 됩니다.

예를 들면, 화면위젯에 생성된 리스트위젯에 키보드가 눌러졌는지 등을 체크하기 위해서 말이죠.

하지만, 매번 컨트롤의 이벤트를 감지하기 위해 서브클래싱을 이용하는 것은 피곤한 절차입니다.

왜냐하면 상속받은 클래스를 따로 만들고, 해당 이벤트 처리 함수를 매번 오버라이딩 (Overriding) 하는 소모적인 작업이 뒤따르기 때문입니다.


개선방안

다행히 QObject (Qt Class 계층의 단군할아버지, 시조) 는 아래와 같은 함수를 가지고 있습니다.

아래는 C++ Qt Document에서 인용한 installEventFilter() 함수 프로토 타입입니다.

[출처 : Qt Document, Link]

(참고로, 저는 PyQt Doc.를  C++ Qt Doc. 를 기준으로 참조하고 있습니다. 왜냐하면 PyQt는 C++로 만들어진 Qt의 Python 바인딩이기 때문입니다. 개인적으로 파이썬을 깊이 이해하려면 C++을 반드시 공부해야 한다고 생각합니다.)

사용법은 모니터링 해야할 클래스의 이벤트 필터 함수를 호출하고 전달인자로 받아서 처리할 QObject 클래스의 포인터를 넣어주면 됩니다.

참고로 C++의 클래스 포인터는 부모 클래스 포인터가 자식 클래스 객체를 가리킬 수 있습니다. 

이를 다형성 (Polymorphism) 이라고 합니다.


그럼 아래 파이썬 예제를 통해 자세히 살펴보겠습니다.

from PyQt5.QtWidgets import QApplication, QWidget, QListWidget, QListWidgetItem, QVBoxLayout
from PyQt5.QtCore import Qt, QEvent
import sys

class Widget(QWidget):

    def __init__(self):
        super().__init__()

        self.lw = QListWidget(self)
        self.lw.addItem( 'Hello' )
        item = QListWidgetItem('Hi')        
        item.setTextAlignment(Qt.AlignRight)
        self.lw.addItem( item )

        vbox = QVBoxLayout()
        vbox.addWidget(self.lw)                
        self.setLayout(vbox)
        self.resize(300,600)

        QApplication.instance().installEventFilter(self)    

    def mousePressEvent(self, e):
        print('Widget Mouse:', e.x(), e.y())

    def eventFilter(self, obj, e):
        if obj==self.lw:           
            print('QListWidget:', e.type()) 

        return super().eventFilter(obj, e)  

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

위 코드를 실행하면 아래와 같은 앱이 실행됩니다.

간단히 위젯위에 리스트위젯을 하나 올린 예제 입니다.

[ 예제 실행 모습 ]

생성자 함수의 마지막 부분 QApplication.instance() Static 함수 호출을 통해 App객체를 얻은 후, installEventFilter() 함수를 호출하는 부분이 있습니다.

이제 리스트 위젯에 이벤트가 발생하면 Override된 eventFilter () 함수가 호출되고, 전달인자로 이벤트가 발생한 객체 (QObject 포인터) 와 발생된 이벤트 (QEvent 포인터) 가 수신됩니다.

리스트 위젯에 키보드를 누르거나, 포커스를 주는 등 행위가 발생하면 아래처럼 이벤트 타입이 출력됩니다.

[ 필터링된 이벤트들 ]

 

굳이 힘들게 서브클래싱을 하지 않아도 QListWidget에서 발생한 이벤트를 Base Widget에서 감시가 가능해졌습니다.

필터링된 이벤트 넘버의 세부적인 내용은 Qt Doc.를 참조 바랍니다. 

[출처 : Qt Doc. QEvent 열거형 일부 ]

감사합니다.

댓글

이 블로그의 인기 게시물

Qt Designer 설치하기

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