Qt에서 Event와 Event Handling¶
Event란?¶
GUI application에서 event 란 사용자 또는 시스템에서 발생하는 모든 종류의 "사건"을 의미함.
- 사용자가 마우스를 클릭함
- 키보드 키를 누름
- 창이 다른 창에 가려졌다가 다시 나타남
- 타이머가 만료됨
- 네트워크 데이터가 도착함
이런 모든 사건들이 event임. GUI application은 이 event들에 반응하면서 동작함.
Event Loop - GUI application의 심장¶
Event Loop가 필요한 이유¶
일반적인 프로그램은 위에서 아래로 순차적으로 실행되고 종료됨. 하지만 GUI application은 다름.
- 사용자가 언제 버튼을 클릭할지, 언제 키를 누를지 알 수 없음.
- 아무 일도 없을 때는 대기하다가 event가 발생하면 즉시 반응해야 함.
- 이를 위해 GUI application은 종료 신호가 올 때까지 계속 "event가 있는지 확인하고 처리"하는 무한 반복 루프 를 실행함.
이 무한 반복 루프가 바로 Event Loop 임.
Event Loop의 시작¶
Qt application에서 event loop는 아래 코드로 시작됨.
app = QApplication(sys.argv)
wnd = MW()
sys.exit(app.exec()) # 여기서 event loop 시작 - 종료 신호가 올 때까지 블로킹됨
app.exec()는 event loop를 시작하며, application이 종료될 때까지 반환되지 않음.- 창을 닫거나
QApplication.quit()가 호출되면 event loop가 종료되고exec()가 반환됨. sys.exit(app.exec())는 event loop 종료 시 반환되는 종료 코드를 OS에 전달함.
Event Loop의 동작 원리¶
Event loop는 background에서 아래와 같은 과정을 반복함.
while (!exit) {
while (!posted_event_queue_is_empty) { // 1. Posted event 처리
process_next_posted_event();
}
while (!spontaneous_event_queue_is_empty) { // 2. Spontaneous event 처리
process_next_spontaneous_event();
}
while (!posted_event_queue_is_empty) { // 3. 2번 처리 중 새로 생긴 Posted event 처리
process_next_posted_event();
}
}
주의 - Event Loop를 블로킹하면 안 됨
- Event loop는 한 번에 하나의 event만 처리함.
- slot 등에서 오래 걸리는 작업(예: 대용량 파일 읽기, 네트워크 요청)을 수행하면 그동안 event loop가 멈춤.
- Event loop가 멈추면 UI가 응답하지 않아 화면이 굳어버리는(freezing) 현상 이 발생함.
- 오래 걸리는 작업은 별도의 thread(
QThread)로 분리하는 것을 권장함.
Event 추상화 - QEvent¶
Qt는 event를 QEvent class로 추상화하며, event 종류에 따라 subclass를 제공함.
Event 발생 및 전달 흐름
- event가 발생하면 Qt는 해당 event를 추상화한
QEventsubclass의 instance를 생성함. - event의 종류에 따라 전달 방식이 다르지만, 최종적으로 처리 대상
QObjectinstance의event()method를 통해 전달됨. event()method는 event를 직접 처리하지 않고, event type에 따라 적절한 event handler 를 호출함.
자주 사용되는 QEvent subclass
| Class | 설명 |
|---|---|
QMouseEvent | 마우스 클릭 / 이동 / 휠 관련 event |
QKeyEvent | 키보드 입력 관련 event |
QPaintEvent | widget 화면 갱신 관련 event |
QResizeEvent | 창 크기 변경 관련 event |
QCloseEvent | 창 닫기 관련 event |
QTimerEvent | 타이머 만료 관련 event |
Event 전달 방식 종류¶
Qt에서 event는 전달 방식에 따라 아래 세 가지로 나뉨.
| 종류 | 발생 주체 | 처리 방식 | 설명 |
|---|---|---|---|
| Spontaneous event | OS | 비동기 | OS가 발생시키며, system queue에 push됨. event loop에 의해 pop되어 처리됨 |
| Posted event | Qt / application | 비동기 | Qt가 관리하는 queue에 push됨. event loop에 의해 pop되어 처리됨 |
| Sent event | Qt / application | 동기 | 발생 즉시 처리 대상 object로 전달되어 동기 처리됨 |
Spontaneous event의 대표적인 예
QMouseEvent,QKeyEvent- OS의 mouse / keyboard interrupt에서 비롯됨.
비동기 처리의 장점 - Compressible event
- 특정 widget의 update가 연속으로 여러 번 발생하는 경우, 비동기 처리에서는 다시 그려야 할 영역의 합집합을 대상으로 한 번의 update로 합쳐지는 최적화 가 가능함.
- 이런 event들을 Compressible event 라고 부르며, paint event / move event 등이 해당됨.
> 동기 처리 및 비동기 처리에 대한 참고자료¶
Event Handling vs Signals and Slots¶
Qt는 event를 처리하는 두 가지 방법을 제공함.
Event Handling¶
Qt가 제공하는 event handler method를 override하여 원하는 동작을 구현하는 방식.
class MW(QWidget):
def mousePressEvent(self, event):
"""마우스 클릭 시 Qt가 자동으로 호출하는 event handler."""
print(f"클릭 위치: {event.position()}")
- widget에서 특정 event가 발생하면 Qt가 자동으로 해당 handler를 호출함.
- low-level 처리이므로 custom widget 개발 등에서 사용됨.
Signals and Slots¶
Qt 고유의 객체 간 통신 메커니즘. 내부적으로 event handling을 사용하지만, 개발자가 event mechanism을 직접 다루지 않아도 됨.
- 구현이 단순하고 직관적임.
- 객체 간 loosely coupling을 유지하면서 효과적인 정보 교환이 가능함.
- 일반적인 GUI application 개발에서는 signals and slots만으로도 충분한 경우가 대부분임.
동기 / 비동기 처리 비교¶
Event Handling과 Signals and Slots의 동기/비동기 처리 방식을 비교하면 아래와 같음.
| 방식 | 처리 방식 |
|---|---|
| Event Handling (Spontaneous / Posted) | 비동기 |
| Event Handling (Sent) | 동기 |
| Signals and Slots (Direct connection, 같은 thread) | 동기 |
| Signals and Slots (Queued connection, 다른 thread) | 비동기 |
즉, Signals and Slots가 동기 처리만 가능하다는 것은 사실이 아님. connection type에 따라 동기/비동기 처리가 모두 가능함.
어떤 방식을 선택할까?¶
Signals and Slots 권장 상황
- 버튼 클릭, 텍스트 변경 등 일반적인 GUI 상호작용 처리.
- 객체 간 통신이 필요한 경우.
- 대부분의 GUI application 개발에서는 이 방식으로 충분함.
Event Handling 권장 상황
- custom widget 개발 - widget의 painting, mouse/keyboard 동작을 직접 제어해야 하는 경우.
- Qt의 기본 event 처리 동작을 세밀하게 override해야 하는 경우.